Matplotlib place y axis on the right with flipped label - python

I want to have the y axis on the right hand side of my plot, but also have the label facing the correct direction. There's many answers that explain the first part, which can be done as follows:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot()
ax.plot([1,2,3,4,5])
ax.set_ylabel("RHS")
ax.yaxis.set_label_position("right")
ax.yaxis.tick_right()
plt.show()
Which produces the following:
But the issue here is the yaxis label on the right hand side is facing outwards, and ideally I would like it to face inwards, something like the following:
Any help with this would be much appreciated!

Just add the following kwargs to your set_ylabel call:
ax.set_ylabel("RHS",rotation=-90,labelpad=15)
which gives the intended output:
If you want to modify label after it has been set, alternatively you can do something like:
yl = ax.set_ylabel("RHS")
ax.yaxis.set_label_position("right")
yl.set_rotation(50)
# do some other stuff
then don't forget to call plt.draw() to make it effective. You may want to have a look at matplotlib text instance properties.

Related

python matplotlib: how to move the scale to the other side of the axis?

I have this weird thing with the scale of the axis showing out of the figure like:
And what I want to have:
How can I move the scale to the other side of the axis?
x=range(len(ticks))
plt.plot(x,phase1,'r^-',label='$\Delta \phi(U1,I1)$')
plt.plot(x,phase2,'go-',label='$\Delta \phi(U2,I2)$')
plt.plot(x,phase3,'b*-',label='$\Delta \phi(U3,I3)$')
plt.xticks(x,ticks,rotation=45)
plt.xlabel('Messung')
plt.ylabel('$\Delta \phi [^\circ]$')
plt.legend()
plt.show()
The tick_params of your axis can be used to control axes label and ticks location. Set direction to in so that they point into the graph.
And here is a great example if you want different y-axis ranges and colours too.
from matplotlib import pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.tick_params(direction='in', length=6, width=2, colors='r', right=True, labelright='on')
plt.show()
You can use plt.tick_params() to adjust the behaviour of the ticks, documentation can be found here.
For your example you want the ticks to appear inside the figure. Therefore add
plt.tick_params(direction="in")
to your code. Example:
x=range(len(ticks))
plt.plot(x,phase1,'r^-',label='$\Delta \phi(U1,I1)$')
plt.plot(x,phase2,'go-',label='$\Delta \phi(U2,I2)$')
plt.plot(x,phase3,'b*-',label='$\Delta \phi(U3,I3)$')
plt.xticks(x,ticks,rotation=45)
plt.xlabel('Messung')
plt.ylabel('$\Delta \phi [^\circ]$')
plt.legend()
plt.tick_params(direction="in") # Set ticks inside the figure
plt.show()
You can get the ticks to appear on the top and right side of the figure too as shown in your second screenshot by adding:
plt.tick_params(direction="in",top="on",right="on")
If you wanted to make all figures in your Python script have this behaviour then you can add the following at the top of your script (this might be of interest):
import matplotlib
matplotlib.rcParams['xtick.direction'] = "in"
matplotlib.rcParams['ytick.direction'] = "in"
This will save you having to call plt.tick_params() for each figure, which is helpful if you generate lots of figures.

matplotlib mark_inset with different data in inset plot

This is a slightly tricky one to explain. Basically, I want to make an inset plot and then utilize the convenience of mpl_toolkits.axes_grid1.inset_locator.mark_inset, but I want the data in the inset plot to be completely independent of the data in the parent axes.
Example code with the functions I'd like to use:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
from mpl_toolkits.axes_grid1.inset_locator import InsetPosition
data = np.random.normal(size=(2000,2000))
plt.imshow(data, origin='lower')
parent_axes = plt.gca()
ax2 = inset_axes(parent_axes, 1, 1)
ax2.plot([900,1100],[900,1100])
# I need more control over the position of the inset axes than is given by the inset_axes function
ip = InsetPosition(parent_axes,[0.7,0.7,0.3,0.3])
ax2.set_axes_locator(ip)
# I want to be able to control where the mark is connected to, independently of the data in the ax2.plot call
mark_inset(parent_axes, ax2, 2,4)
# plt.savefig('./inset_example.png')
plt.show()
The example code produces the following image:
So to sum up: The location of the blue box is entire controlled by the input data to ax2.plot(). I would like to manually place the blue box and enter whatever I want into ax2. Is this possible?
quick edit: to be clear, I understand why inset plots would have the data linked, as that's the most likely usage. So if there's a completely different way in matplotlib to accomplish this, do feel free to reply with that. However, I am trying to avoid manually placing boxes and lines to all of the axes I would place, as I need quite a few insets into a large image.
If I understand correctly, you want an arbitrarily scaled axis at a given position that looks like a zoomed inset, but has no connection to the inset marker's position.
Following your approach you can simply add another axes to the plot and position it at the same spot of the true inset, using the set_axes_locator(ip) function. Since this axis is drawn after the original inset, it will be on top of it and you'll only need to hide the tickmarks of the original plot to let it disappear completely (set_visible(False) does not work here, as it would hide the lines between the inset and the marker position).
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes, mark_inset, InsetPosition
data = np.random.normal(size=(200,200))
plt.imshow(data, origin='lower')
parent_axes = plt.gca()
ax2 = inset_axes(parent_axes, 1, 1)
ax2.plot([60,75],[90,110])
# hide the ticks of the linked axes
ax2.set_xticks([])
ax2.set_yticks([])
#add a new axes to the plot and plot whatever you like
ax3 = plt.gcf().add_axes([0,0,1,1])
ax3.plot([0,3,4], [2,3,1], marker=ur'$\u266B$' , markersize=30, linestyle="")
ax3.set_xlim([-1,5])
ax3.set_ylim([-1,5])
ip = InsetPosition(parent_axes,[0.7,0.7,0.3,0.3])
ax2.set_axes_locator(ip)
# set the new axes (ax3) to the position of the linked axes
ax3.set_axes_locator(ip)
# I want to be able to control where the mark is connected to, independently of the data in the ax2.plot call
mark_inset(parent_axes, ax2, 2,4)
plt.show()
FWIW, I came up with a hack that works.
In the source code for inset_locator, I added a version of mark_inset that takes another set of axes used to define the TransformedBbox:
def mark_inset_hack(parent_axes, inset_axes, hack_axes, loc1, loc2, **kwargs):
rect = TransformedBbox(hack_axes.viewLim, parent_axes.transData)
pp = BboxPatch(rect, **kwargs)
parent_axes.add_patch(pp)
p1 = BboxConnector(inset_axes.bbox, rect, loc1=loc1, **kwargs)
inset_axes.add_patch(p1)
p1.set_clip_on(False)
p2 = BboxConnector(inset_axes.bbox, rect, loc1=loc2, **kwargs)
inset_axes.add_patch(p2)
p2.set_clip_on(False)
return pp, p1, p2
Then in my original-post code I make an inset axis where I want the box to be, pass it to my hacked function, and make it invisible:
# location of desired axes
axdesire = inset_axes(parent_axes,1,1)
axdesire.plot([100,200],[100,200])
mark_inset_hack(parent_axes, ax2, axdesire, 2,4)
axdesire.set_visible(False)
Now I have a marked box at a different location in data units than the inset that I'm marking:
It is certainly a total hack, and at this point I'm not sure it's cleaner than simply drawing lines manually, but I think for a lot of insets this will keep things conceptually cleaner.
Other ideas are still welcome.

ValueError when using matplotlib tight_layout()

Ok, this is my first time asking a question on here, so please be patient with me ;-)
I'm trying to create a series of subplots (with two y-axes each) in a figure using matplotlib and then saving that figure. I'm using GridSpec to create a grid for the subplots and realised that they're overlapping a little, which I don't want. So I'm trying to use tight_layout() to sort this out, which according to the matplotlib documentation should work just fine. Simplifying things a bit, my code looks something like this:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure(num=None, facecolor='w', edgecolor='k')
grid = gridspec.GridSpec(2, numRows)
# numRows comes from the number of subplots required
# then I loop over all the data files I'm importing and create a subplot with two y-axes each time
ax1 = fig.add_subplot(grid[column, row])
# now I do all sorts of stuff with ax1...
ax2 = ax1.twinx()
# again doing some stuff here
After the loop for data processing is done and I have created all the subplots, I eventually end with
fig.tight_layout()
fig.savefig(str(location))
As far as I can work out, this should work, however when calling tight_layout(), I get a ValueError from the function self.subplotpars: left cannot be >= right. My question is: How do I figure out what's causing this error and how do I fix it?
I've had this error before, and I have a solution that worked for me. I'm not sure if it will work for you though. In matplotlib, the command
plt.fig.subplots_adjust()
can be used to sort of stretch the plot. The left and bottom stretch more the smaller the number gets, while the top and right stretch more the greater the number is. So if left is greater than or equal to the right, or bottom is greater than or equal to the top, than the graph would kind of flip over. I adjusted my command to look like this:
fig = plt.figure()
fig.subplots_adjust(bottom = 0)
fig.subplots_adjust(top = 1)
fig.subplots_adjust(right = 1)
fig.subplots_adjust(left = 0)
Then you can fill in your own numbers to adjust this, as long as you keep the left and bottom smaller. I hope this fixes your problem.

physically stretch plot in horizontal direction in python

I want a simple x,y plot created with matplotlib stretched physically in x-direction.
The intention is to get a result were it is easier for me to detect features in the signal.
So I don't want to change any scales or values or limits. Just change the distance between two gridpoint in my output file...
I want to do that on four subplots which should have the same size afterwards.
Thanks in advance... I tried for hours now and I think one of you could probably help me...
David Zwicker already solved my problem in this special case, thanks a lot for that, but in general... If I plot 2 subplots like in this code:
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
plot(u_av,z)
ax2 = fig.add_subplot(1,2,2)
plot(pgrd_av,z)
clf()
and want to stretch only one of them. What can I do?
You can change the figure size by using plt.figure(figsize=(20,5)). See the documentation of the figure command.
I know, this is a bit out of the context. But if someone is looking for a solution while using pandas plot which internally uses matplotlib. Here is the solution.
df.plot('col_x', 'col_y', title='stretched_plot', figsize=(20, 1))
You can directly add axes to the canvas at an arbitrary position with plt.axes(). For instance:
ax1 = plt.axes([0, 0, 3, 0.5])
ax2 = plt.axes([0, 0.6, 1, 1])
You can do this:
x = 1.5 # or your needed amount
plt.plot(x_array * x, y_array)
Your line or graph will move to the right depending on your x value

Space between Y-axis and First X tick

Matplotlib newbie here.
I have the following code:
from pylab import figure, show
import numpy
fig = figure()
ax = fig.add_subplot(111)
plot_data=[1.7,1.7,1.7,1.54,1.52]
xdata = range(len(plot_data))
labels = ["2009-June","2009-Dec","2010-June","2010-Dec","2011-June"]
ax.plot(xdata,plot_data,"b-")
ax.set_xticks(range(len(labels)))
ax.set_xticklabels(labels)
ax.set_yticks([1.4,1.6,1.8])
fig.canvas.draw()
show()
When you run that code, the resulting chart has a run-in with the first tick label (2009-June) and the origin. How can I get the graph to move over to make that more readable? I tried to put dummy data in, but then Matplotlib (correctly) treats that as data.
add two limits to the x and y axes to shift the tick labels a bit.
# grow the y axis down by 0.05
ax.set_ylim(1.35, 1.8)
# expand the x axis by 0.5 at two ends
ax.set_xlim(-0.5, len(labels)-0.5)
the result is
Because tick labels are text objects you can change their alignment. However to get access to the text properties you need to go through the set_yticklabels function. So add the line:
ax.set_yticklabels([1.4,1.6,1.8],va="bottom")
after your set_yticks call. Alternatively if you go through the pylab library directly, instead of accessing the function through the axes object, you can just set that in one line:
pylab.yticks([1.4,1.6,1.8],va="bottom")
I suggest change Y axis limits:
ax.set_ylim([1.2, 1.8])

Categories

Resources