Same length of ticks in multiplot - python

How to set to have the same scale/length of ticks in all subplots? I would like to set length of all xticks according to the forth subplot. I mean that all axis named y will have the same space between ticks 0 and 2, all axis named x will have the same space between -1 and 0. Maybe it would be sufficient to set plot as squares. How please?
import numpy as np
import matplotlib.pyplot as plt
from numpy import array
import matplotlib as mpl
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
# Plot figure with size
fig, ax = plt.subplots(sharex=True)
plt.figure(figsize=(12, 9))
# Subplots
fig1 = plt.subplot(231)
plt.plot(x, y**2)
fig1.set_xlim(0e-13,2e-13)
fig1.set_ylim(-1.15e-14,0.01e-14)
fig2=plt.subplot(232)
plt.plot(x, y**2)
fig2.set_xlim(0e-13,2e-13)
fig2.set_ylim(-7.3e-15,7.3e-15)
fig3=plt.subplot(233)
plt.plot(x, y**2)
fig3.set_ylim(0e-13,1.2e-13)
fig3.set_xlim(0e-13,2e-13)
# Subplots with arrows
fig4=plt.subplot(234)
plt.plot(x, y**2)
fig4.set_xlim(-1.15e-14,0.01e-14)
fig4.set_ylim(-7.3e-15,7.3e-15)
fig5=plt.subplot(235)
plt.plot(x, y**2)
fig5.set_xlim(-7.3e-15,7.3e-15)
fig5.set_ylim(0e-13,1.2e-13)
plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
fig6=plt.subplot(236)
plt.plot(x, y**2)
fig6.set_xlim(-1.5e-14,0e-14)
fig6.set_ylim(0e-13,1.2e-13)
plt.show()

The way to achieve this is outlined best by this excellent answer by #ImportanceOfBeingErnest. Basically you manually calculate the scaling to adhere to the ratio between the y and x limits of each existing axis by something like
fig1.set_aspect(np.diff(fig1.get_xlim())/np.diff(fig1.get_ylim()))
But please note that this must be done after any calls to set_ylim() and set_xlim() as it must use the final limits in order to correctly calculate the requisite ratio. set_xticks() and set_yticks() can safely be called before or after with the same effect.
Applying this to each of the six axes will produce

Related

Overlapping y axis lable in matplotlib

I have these code here to create an xgboost feature importance plot with more than 40 variables :
plot_importance(xgb_model)
plt.show()
However, I got a plot with overlapping y-axis labels and it was hard to read. The figsize=() argument did not seem to work.
Is there a way to make this plot readable?
Definitely go with figsize. You can see that because if you interactively change the window size you observe that the ticks labels d on't overlap anymore.
You can also change the font properties, see https://stackoverflow.com/a/11386056/13636407.
import numpy as np
import matplotlib.pyplot as plt
def plot_sin(figsize):
x = np.linspace(0, 4 * np.pi)
y = np.sin(x)
fig, ax = plt.subplots(figsize=figsize)
ax.plot(x, y)
ax.set_yticks(np.arange(-1.15, 1.15, 0.05))
ax.set_title(f"{figsize = }")
plot_sin(figsize=(12, 4))
plot_sin(figsize=(12, 10))
plt.show()

Legend specifying 3d position in 3D axes matplotlib

I have a scatter 3d plot using matplotlib.
What I'm trying to do is to position the legend inside the plot. I have read the documentation and it seems that is only possible to select predefined positions or only specify x and y coordinates.
Is there a way to position the legend specifying the 3 coordinates?
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#more code
ax.legend(loc=(0.5,0.5,0.5), frameon=0)
The last line is what I thought might work but obviously is not working.
This is what I've now:
I'm trying to position the legend inside the axes, sort of like:
I reached that position by trial and error using ax.legend(loc=(0.15,0.65),frameon=0) because the legend doesn't move as the axes are rotated. The issue is that I'll be doing several plots thus I'm trying to avoid the trial and error approach.
Thanks.
To place the legend in a 3D plot using data coordinates, one may first get the projected coordinates of a point in 3D space using
mpl_toolkits.mplot3d.proj3d.proj_transform(x,y,z, ax.get_proj())
and provide those to the bbox_to_anchor argument of the legend. Than changing the bbox_transform to the data coordinate system produces the desired plot.
The following places the lower left corner of the legend at position (70,1000,80) in data coordinates.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D, proj3d
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = 25 * r * np.sin(theta)
y = 350* r * np.cos(theta)
ax.plot(x, y, 70*z, label='parametric curve')
ax.plot(x*.6, y*0.5, 70*z, label='parametric curve 2')
f = lambda x,y,z: proj3d.proj_transform(x,y,z, ax.get_proj())[:2]
ax.legend(loc="lower left", bbox_to_anchor=f(70,1000,80),
bbox_transform=ax.transData)
plt.show()

Difference between axis('equal') and axis('scaled') in matplotlib

In the reference, they are described as:
axis('equal')
changes limits of x or y axis so that equal increments of x and y have the same length; a circle is
circular.:
axis('scaled')
achieves the same result by changing the dimensions of the plot box instead of the axis data limits.:
But I did not understand the part 'by changing the dimensions of the plot box'.
So I compared directly
import numpy as np
import matplotlib.pyplot as plt
plt.close('all')
x = np.array(np.linspace(-np.pi, np.pi))
y = np.sin(x)
ax1 = plt.subplot(2, 1, 1)
ax1 = plt.plot(x, y)
plt.axis('scaled')
ax1 = plt.subplot(2, 1, 2)
plt.plot(x, y)
plt.axis('equal')
There is only a slight difference that the width is shorter when plotted with plt.axis('scaled').
How can I know the difference better?
I think the difference becomes more apparent, if you use different data.
import numpy as np
import matplotlib.pyplot as plt
x = np.array(np.linspace(-np.pi, np.pi))
y = np.sin(x)*np.pi
ax1 = plt.subplot(2, 1, 1)
ax1 = plt.plot(x, y)
plt.axis('scaled')
ax1 = plt.subplot(2, 1, 2)
plt.plot(x, y)
plt.axis('equal')
plt.show()
So the difference is if the axes around the plot are changed according to the aspect, or if they stay the same as in a usual subplot and are scaled such, that the aspect of the plot data is equal.

Matplotlib - Plot line with width equivalent to a range of values, not just one single

What I want is quite simply adding to a normal pyplot.plot a horizontal line with the width equal to a range of values that I give. Preferably I also want to be able to adjust the transparency of this "block", that is the wide horizontal line.
I'd recommend to just use pyplot.fill_between():
import matplotlib.pyplot as pl
import numpy as np
fig = pl.figure()
ax = fig.add_subplot(111)
x = np.random.random(10)
y = np.random.random(10)
ax.scatter(x, y)
ax.fill_between(ax.get_xlim(), min(y), max(y), color='k', alpha=0.2)

Matplotlib conversion from data units to axis units

I'm trying to plot some data with Matplotlib (Python library) and to add an horizontal line, that would not cover the full axis range but start around the middle and finish on the right axis.
I am using:
plt.axhline(y=1.75,xmin=0.5)
where y specifies the height of the line in data units, but xmin (as well as xmax) need to be defined in axis units (=0 for the beginning of axis and =1 at the end). Though I only know the point I want my line to start in data units, is there a method/function to convert from one to the other?
Just draw a line with plt
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0.2,10,100)
fig, ax = plt.subplots()
ax.plot(x, 1/x)
ax.plot(x, np.log(x))
ax.set_aspect('equal')
ax.grid(True, which='both')
y = 1.25
xmin = 2
xmax = ax.get_xlim()[1]
ax.plot([xmin, xmax], [y, y], color='k')
which gives me:

Categories

Resources