Removing or adjusting ticks for inset_axis - python

TL;DR: I cannot remove or adjust xticks from inset_axis.
I was trying to prepare a zoom-in plot, where a box will display a zoomed version of the plot. However, the x-ticks of the zoomed in plot were too entangled and I decided to manually assign them.
This is a snip from the original plot.
So I tried the following lines:
inset_axe.set_xticks([])
inset_axe.set_yticks([])
It indeed removed the yticks, but xticks are not affected.
Here is a minimum working example. The issue persists in the MWE as well.
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import numpy as np
import matplotlib.pyplot as plt
#####Just creating random N,Q function
a=0.1
Q=np.linspace(-5,4,1000)
M=a*np.ones(2000)
P=1.4**4*np.ones(2000)+a
N=[1.4**(x)+a for x in Q]
N=np.asarray(list(M)+N+list(P))
Q=np.logspace(-9,6,5000)
####################################
g, axes = plt.subplots(1)
inset_axe = inset_axes(axes,width="60%", height="25%", loc='lower left',
bbox_to_anchor=(0.6,0.15,0.7,.7), bbox_transform=axes.transAxes)
inset_axe.semilogx(Q[2200:2400],N[2200:2400])
inset_axe.set_yticks([])
inset_axe.set_xticks([])
axes.semilogx(Q,N)
plt.show()
Is this a bug or do I have a small mistake that I cannot see? Is there a way around this?
If it helps, I use Microsoft VS and matplotlib version is 3.3.3.

Most of your ticks are minor.
You may also want to use the more lightweight axes.inset_axes:
import numpy as np
import matplotlib.pyplot as plt
#####Just creating random N,Q function
a=0.1
Q=np.linspace(-5,4,1000)
M=a*np.ones(2000)
P=1.4**4*np.ones(2000)+a
N=[1.4**(x)+a for x in Q]
N=np.asarray(list(M)+N+list(P))
Q=np.logspace(-9,6,5000)
####################################
g, ax = plt.subplots(1)
inset_axe = ax.inset_axes([0.6, 0.2, 0.2, 0.2], transform=ax.transAxes)
inset_axe.semilogx(Q[2200:2400], N[2200:2400])
inset_axe.set_yticks([])
#################
inset_axe.set_xticks([], minor=True)
#################
inset_axe.set_xticks([])
ax.semilogx(Q,N)
ax.set_xticks([])
plt.show()

Related

Matplotlib animation on spyder python output a single image

I wanted to make an animation in spyder but i just get a static plot. this is the code.
import numpy as np
import matplotlib.pyplot as plt
plt.figure(1)
plt.clf()
plt.axis([-10,10,-10,10])
n=10
pos=(20*np.random.sample(n*2)-10).reshape(n,2)
vel=(0.3*np.random.normal(size=n*2)).reshape(n,2)
sizes=100*np.random.sample(n)+100
colors=np.random.sample([n,4]
circles=plt.scatter(pos[:,0], pos[:,1], marker='o', s=sizes, c=colors)
for i in range(100):
pos=pos+vel
bounce=abs(pos)>10
vel[bounce] = -vel[bounce]
circles.set_offsets(pos)
plt.draw()
plt.show()
this is what i get, I've tried with %matplotlib qt5 but it doesn't change the output and the stays still1]1
There are two things you need to do to make the animation work.
First, is that you need to show the figure once the animation made, so plt.show() should get out of the for loop.
Also to be able to see the frames, you need to put a small amount of time between them, which an be achieved by adding, for example, plt.pause(t) (t in seconds) in between the frames.
The code shown below is the edited code generating an animated plot.
import numpy as np
import matplotlib.pyplot as plt
plt.figure(1)
plt.clf()
plt.axis([-10,10,-10,10])
n=10
pos=(20*np.random.sample(n*2)-10).reshape(n,2)
vel=(0.3*np.random.normal(size=n*2)).reshape(n,2)
sizes=100*np.random.sample(n)+100
colors=np.random.sample([n,4])
circles=plt.scatter(pos[:,0], pos[:,1], marker='o', s=sizes, c=colors)
for i in range(100):
pos=pos+vel
bounce=abs(pos)>10
vel[bounce] = -vel[bounce]
circles.set_offsets(pos)
plt.draw()
plt.pause(0.05)
plt.show()

Power BI shows only one patch from Matplotlib patch collection

I am trying to show a matplotlib plot in Power BI (desktop). It includes Patchcollection. Running the standalone python code gives this:
But in Power BI, the same code results in this:
Attaching sample code:
from matplotlib import pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.patches import Circle
import matplotlib.collections
import numpy as np
N = dataset.shape[0]
patches = []
# code to fill in the list patches goes here
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal')
colors = 100*np.random.random(N)
p = matplotlib.collections.PatchCollection(patches, cmap=matplotlib.cm.jet, alpha=0.4)
p.set_array(colors)
ax.add_collection(p)
plt.autoscale(enable='True', axis='both')
plt.show()
Any help will be appreciated. Thank you!
Edit: Just noticed that the values got doubled for that single patch. Very strange.
Figured out the issue. I had to choose 'Don't Summarize' in the values tab for each field.

How to properly display sufficient tick markers using plt.savefig?

After running the code below, the axis tick markers all overlap with each other. At this time, each marker could still have good resolution when zooming popped up by plt.show(). However, the figure saved by plt.savefig('fig.png') would lost its resolution. Can this also be optimised?
from matplotlib.ticker import FuncFormatter
from matplotlib.pyplot import show
import matplotlib.pyplot as plt
import numpy as np
a=np.random.random((1000,1000))
# create scaled formatters / for Y with Atom prefix
formatterY = FuncFormatter(lambda y, pos: 'Atom {0:g}'.format(y))
formatterX = FuncFormatter(lambda x, pos: '{0:g}'.format(x))
# apply formatters
fig, ax = plt.subplots()
ax.yaxis.set_major_formatter(formatterY)
ax.xaxis.set_major_formatter(formatterX)
plt.imshow(a, cmap='Reds', interpolation='nearest')
# create labels
plt.xlabel('nanometer')
plt.ylabel('measure')
plt.xticks(list(range(0, 1001,10)))
plt.yticks(list(range(0, 1001,10)))
plt.savefig('fig.png',bbox_inches='tight')
plt.show()
I think you can solve it by setting the size of the figure, e.g.
fig, ax = plt.subplots()
fig.set_size_inches(15., 15.)
As pointed out by #PatrickArtner in the comments, you can then also avoid the overlap of x-ticks by
plt.xticks(list(range(0, 1001, 10)), rotation=90)
instead of
plt.xticks(list(range(0, 1001,10)))
The rest of the code is completely unchanged; the output then looks reasonable (but is too large to upload here).

Getting legend in seaborn jointplot

I'm interested in using the seaborn joint plot for visualizing correlation between two numpy arrays. I like the visual distinction that the kind='hex' parameter gives, but I would also like to know the actual count that different shades correspond to. Does anyone know how to put this legend on the side or even on the plot? I tried looking at the documentation and couldn't find it.
Thanks!
EDIT: updated to work with new Seaborn ver.
You need to do it manually by making a new axis with add_axes and then pass the name of the ax to plt.colorbar().
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
x = np.random.normal(0.0, 1.0, 1000)
y = np.random.normal(0.0, 1.0, 1000)
hexplot = sns.jointplot(x, y, kind="hex")
plt.subplots_adjust(left=0.2, right=0.8, top=0.8, bottom=0.2) # shrink fig so cbar is visible
# make new ax object for the cbar
cbar_ax = hexplot.fig.add_axes([.85, .25, .05, .4]) # x, y, width, height
plt.colorbar(cax=cbar_ax)
plt.show()
Sources: I almost gave up after I read a dev say that the
"work/benefit ratio [to implement colorbars] is too high"
but then I eventually found this solution in another issue.
The following has worked for me:
t1 = sns.jointplot(data=df, x="originalestimate_hours", y="working_hours_per_day_created_target", hue="status")
t1.ax_joint.legend_._visible=False
t1.fig.legend(bbox_to_anchor=(1, 1), loc=2)

How to zoomed a portion of image and insert in the same plot in matplotlib

I would like to zoom a portion of data/image and plot it inside the same figure. It looks something like this figure.
Is it possible to insert a portion of zoomed image inside the same plot. I think it is possible to draw another figure with subplot but it draws two different figures. I also read to add patch to insert rectangle/circle but not sure if it is useful to insert a portion of image into the figure. I basically load data from the text file and plot it using a simple plot commands shown below.
I found one related example from matplotlib image gallery here but not sure how it works. Your help is much appreciated.
from numpy import *
import os
import matplotlib.pyplot as plt
data = loadtxt(os.getcwd()+txtfl[0], skiprows=1)
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.semilogx(data[:,1],data[:,2])
plt.show()
Playing with runnable code is one of the
fastest ways to learn Python.
So let's start with the code from the matplotlib example gallery.
Given the comments in the code, it appears the code is broken up into 4 main stanzas.
The first stanza generates some data, the second stanza generates the main plot,
the third and fourth stanzas create the inset axes.
We know how to generate data and plot the main plot, so let's focus on the third stanza:
a = axes([.65, .6, .2, .2], axisbg='y')
n, bins, patches = hist(s, 400, normed=1)
title('Probability')
setp(a, xticks=[], yticks=[])
Copy the example code into a new file, called, say, test.py.
What happens if we change the .65 to .3?
a = axes([.35, .6, .2, .2], axisbg='y')
Run the script:
python test.py
You'll find the "Probability" inset moved to the left.
So the axes function controls the placement of the inset.
If you play some more with the numbers you'll figure out that (.35, .6) is the
location of the lower left corner of the inset, and (.2, .2) is the width and
height of the inset. The numbers go from 0 to 1 and (0,0) is the located at the
lower left corner of the figure.
Okay, now we're cooking. On to the next line we have:
n, bins, patches = hist(s, 400, normed=1)
You might recognize this as the matplotlib command for drawing a histogram, but
if not, changing the number 400 to, say, 10, will produce an image with a much
chunkier histogram, so again by playing with the numbers you'll soon figure out
that this line has something to do with the image inside the inset.
You'll want to call semilogx(data[3:8,1],data[3:8,2]) here.
The line title('Probability')
obviously generates the text above the inset.
Finally we come to setp(a, xticks=[], yticks=[]). There are no numbers to play with,
so what happens if we just comment out the whole line by placing a # at the beginning of the line:
# setp(a, xticks=[], yticks=[])
Rerun the script. Oh! now there are lots of tick marks and tick labels on the inset axes.
Fine. So now we know that setp(a, xticks=[], yticks=[]) removes the tick marks and labels from the axes a.
Now, in theory you have enough information to apply this code to your problem.
But there is one more potential stumbling block: The matplotlib example uses
from pylab import *
whereas you use import matplotlib.pyplot as plt.
The matplotlib FAQ says import matplotlib.pyplot as plt
is the recommended way to use matplotlib when writing scripts, while
from pylab import * is for use in interactive sessions. So you are doing it the right way, (though I would recommend using import numpy as np instead of from numpy import * too).
So how do we convert the matplotlib example to run with import matplotlib.pyplot as plt?
Doing the conversion takes some experience with matplotlib. Generally, you just
add plt. in front of bare names like axes and setp, but sometimes the
function come from numpy, and sometimes the call should come from an axes
object, not from the module plt. It takes experience to know where all these
functions come from. Googling the names of functions along with "matplotlib" can help.
Reading example code can builds experience, but there is no easy shortcut.
So, the converted code becomes
ax2 = plt.axes([.65, .6, .2, .2], axisbg='y')
ax2.semilogx(t[3:8],s[3:8])
plt.setp(ax2, xticks=[], yticks=[])
And you could use it in your code like this:
from numpy import *
import os
import matplotlib.pyplot as plt
data = loadtxt(os.getcwd()+txtfl[0], skiprows=1)
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.semilogx(data[:,1],data[:,2])
ax2 = plt.axes([.65, .6, .2, .2], axisbg='y')
ax2.semilogx(data[3:8,1],data[3:8,2])
plt.setp(ax2, xticks=[], yticks=[])
plt.show()
The simplest way is to combine "zoomed_inset_axes" and "mark_inset", whose description and
related examples could be found here:
Overview of AxesGrid toolkit
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
import numpy as np
def get_demo_image():
from matplotlib.cbook import get_sample_data
import numpy as np
f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False)
z = np.load(f)
# z is a numpy array of 15x15
return z, (-3,4,-4,3)
fig, ax = plt.subplots(figsize=[5,4])
# prepare the demo image
Z, extent = get_demo_image()
Z2 = np.zeros([150, 150], dtype="d")
ny, nx = Z.shape
Z2[30:30+ny, 30:30+nx] = Z
# extent = [-3, 4, -4, 3]
ax.imshow(Z2, extent=extent, interpolation="nearest",
origin="lower")
axins = zoomed_inset_axes(ax, 6, loc=1) # zoom = 6
axins.imshow(Z2, extent=extent, interpolation="nearest",
origin="lower")
# sub region of the original image
x1, x2, y1, y2 = -1.5, -0.9, -2.5, -1.9
axins.set_xlim(x1, x2)
axins.set_ylim(y1, y2)
plt.xticks(visible=False)
plt.yticks(visible=False)
# draw a bbox of the region of the inset axes in the parent axes and
# connecting lines between the bbox and the inset axes area
mark_inset(ax, axins, loc1=2, loc2=4, fc="none", ec="0.5")
plt.draw()
plt.show()
The nicest way I know of to do this is to use mpl_toolkits.axes_grid1.inset_locator (part of matplotlib).
There is a great example with source code here: https://github.com/NelleV/jhepc/tree/master/2013/entry10
The basic steps to zoom up a portion of a figure with matplotlib
import numpy as np
from matplotlib import pyplot as plt
# Generate the main data
X = np.linspace(-6, 6, 1024)
Y = np.sinc(X)
# Generate data for the zoomed portion
X_detail = np.linspace(-3, 3, 1024)
Y_detail = np.sinc(X_detail)
# plot the main figure
plt.plot(X, Y, c = 'k')
# location for the zoomed portion
sub_axes = plt.axes([.6, .6, .25, .25])
# plot the zoomed portion
sub_axes.plot(X_detail, Y_detail, c = 'k')
# insert the zoomed figure
# plt.setp(sub_axes)
plt.show()

Categories

Resources