I have a bunch of MATLAB code from my MS thesis which I now want to convert to Python (using numpy/scipy and matplotlib) and distribute as open-source. I know the similarity between MATLAB and Python scientific libraries, and converting them manually will be not more than a fortnight (provided that I work towards it every day for some time). I was wondering if there was already any tool available which can do the conversion.
For N bins, the bin edges are specified by list of N+1 values where the first N give the lower bin edges and the +1 gives the upper edge of the last bin.
Code:
from numpy import np; from pylab import *
bin_size = 0.1; min_edge = 0; max_edge = 2.5
N = (max_edge-min_edge)/bin_size; Nplus1 = N + 1
bin_list = np.linspace(min_edge, max_edge, Nplus1)
Note that linspace produces array from min_edge to max_edge broken into N+1 values or N bins
回答 2
我猜最简单的方法是计算您拥有的数据的最小值和最大值,然后计算L = max - min。然后L,用所需的箱宽度除(我假设这就是箱大小),然后将该值的上限用作箱数。
I guess the easy way would be to calculate the minimum and maximum of the data you have, then calculate L = max - min. Then you divide L by the desired bin width (I’m assuming this is what you mean by bin size) and use the ceiling of this value as the number of bins.
I had the same issue as OP (I think!), but I couldn’t get it to work in the way that Lastalda specified. I don’t know if I have interpreted the question properly, but I have found another solution (it probably is a really bad way of doing it though).
I am currently practicing matplotlib. This is the first example I practice.
#!/usr/bin/python
import matplotlib.pyplot as plt
radius = [1.0, 2.0, 3.0, 4.0]
area = [3.14159, 12.56636, 28.27431, 50.26544]
plt.plot(radius, area)
plt.show()
When I run this script with python ./plot_test.py, it shows plot correctly. However, I run it by itself, ./plot_test.py, it throws the followings:
Traceback (most recent call last):
File "./plot_test.py", line 3, in <module>
import matplotlib.pyplot as plt
ImportError: No module named matplotlib.pyplot
Does python look for matplotlib in different locations?
You have two pythons installed on your machine, one is the standard python that comes with Mac OSX and the second is the one you installed with ports (this is the one that has matplotlib installed in its library, the one that comes with macosx does not).
/usr/bin/python
Is the standard mac python and since it doesn’t have matplotlib you should always start your script with the one installed with ports.
If python your_script.py works then change the #! to:
#!/usr/bin/env python
Or put the full path to the python interpreter that has the matplotlib installed in its library.
Step 2: Take note of where the file got saved and cd the directory from command prompt. Run the get-pip.py script to install pip.
You can write in cmd this line within quotes: “python .\get-pip.py”
I had a similar issue that I resolved and here is my issue:
I set everything up on python3 but I was using python to call my file for example:
I was typing “python mnist.py” …since I have everything on python3 it was thinking I was trying to use python 2.7
The correction:
“python3 mnist.py” – the 3 made all the difference
I’m by no means an expert in python or pip, but there is definitely a difference between pip and pip3 (pip is tied to python 2.7) (pip3 is tied to python 3.6)
so when installing for 2.7 do: pip install
when installing for 3.6 do: pip3 install
and when running your code for 2.7 do: python
when running your code for 3.6 do: python3
# Setting PATH for Python 3.6# The original version is saved in .bash_profile.pysave
PATH="/Library/Frameworks/Python.framework/Versions/3.6/bin:${PATH}"
export PATH
I bashed my head on this for hours until I thought about checking my .bash_profile. I didn’t have a path listed for python3 so I added the following code:
# Setting PATH for Python 3.6
# The original version is saved in .bash_profile.pysave
PATH="/Library/Frameworks/Python.framework/Versions/3.6/bin:${PATH}"
export PATH
And then re-installed matplotlib with sudo pip3 install matplotlib. All is working beautifully now.
import numpy as npimport matplotlib as plt
x = arange(5)
y = np.exp(5)
plt.figure()
plt.plot(x, y)
z = np.sin(x)
plt.figure()
plt.plot(x, z)
w = np.cos(x)
plt.figure("""first figure""")# Here's the part I need
plt.plot(x, w)
I want to plot data, then create a new figure and plot data2, and finally come back to the original plot and plot data3, kinda like this:
import numpy as np
import matplotlib as plt
x = arange(5)
y = np.exp(5)
plt.figure()
plt.plot(x, y)
z = np.sin(x)
plt.figure()
plt.plot(x, z)
w = np.cos(x)
plt.figure("""first figure""") # Here's the part I need
plt.plot(x, w)
import matplotlib.pyplot as pltimport numpy as np
x = np.arange(5)
y = np.exp(x)
fig1, ax1 = plt.subplots()
ax1.plot(x, y)
ax1.set_title("Axis 1 title")
ax1.set_xlabel("X-label for axis 1")
z = np.sin(x)
fig2,(ax2, ax3)= plt.subplots(nrows=2, ncols=1)# two axes on figure
ax2.plot(x, z)
ax3.plot(x,-z)
w = np.cos(x)
ax1.plot(x, w)# can continue plotting on the first axis
If you find yourself doing things like this regularly it may be worth investigating the object-oriented interface to matplotlib. In your case:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(5)
y = np.exp(x)
fig1, ax1 = plt.subplots()
ax1.plot(x, y)
ax1.set_title("Axis 1 title")
ax1.set_xlabel("X-label for axis 1")
z = np.sin(x)
fig2, (ax2, ax3) = plt.subplots(nrows=2, ncols=1) # two axes on figure
ax2.plot(x, z)
ax3.plot(x, -z)
w = np.cos(x)
ax1.plot(x, w) # can continue plotting on the first axis
It is a little more verbose but it’s much clearer and easier to keep track of, especially with several figures each with multiple subplots.
回答 1
调用时figure,只需为图编号即可。
x = arange(5)
y = np.exp(5)
plt.figure(0)
plt.plot(x, y)
z = np.sin(x)
plt.figure(1)
plt.plot(x, z)
w = np.cos(x)
plt.figure(0)# Here's the part I need
plt.plot(x, w)
x = arange(5)
y = np.exp(5)
plt.figure(0)
plt.plot(x, y)
z = np.sin(x)
plt.figure(1)
plt.plot(x, z)
w = np.cos(x)
plt.figure(0) # Here's the part I need
plt.plot(x, w)
Edit: Note that you can number the plots however you want (here, starting from 0) but if you don’t provide figure with a number at all when you create a new one, the automatic numbering will start at 1 (“Matlab Style” according to the docs).
回答 2
但是,编号从开始1,因此:
x = arange(5)
y = np.exp(5)
plt.figure(1)
plt.plot(x, y)
z = np.sin(x)
plt.figure(2)
plt.plot(x, z)
w = np.cos(x)
plt.figure(1)# Here's the part I need, but numbering starts at 1!
plt.plot(x, w)
x = arange(5)
y = np.exp(5)
plt.figure(1)
plt.plot(x, y)
z = np.sin(x)
plt.figure(2)
plt.plot(x, z)
w = np.cos(x)
plt.figure(1) # Here's the part I need, but numbering starts at 1!
plt.plot(x, w)
Also, if you have multiple axes on a figure, such as subplots, use the axes(h) command where h is the handle of the desired axes object to focus on that axes.
(don’t have comment privileges yet, sorry for new answer!)
One way I found after some struggling is creating a function which gets data_plot matrix, file name and order as parameter to create boxplots from the given data in the ordered figure (different orders = different figures) and save it under the given file_name.
I am using matplotlib to make scatter plots. Each point on the scatter plot is associated with a named object. I would like to be able to see the name of an object when I hover my cursor over the point on the scatter plot associated with that object. In particular, it would be nice to be able to quickly see the names of the points that are outliers. The closest thing I have been able to find while searching here is the annotate command, but that appears to create a fixed label on the plot. Unfortunately, with the number of points that I have, the scatter plot would be unreadable if I labeled each point. Does anyone know of a way to create labels that only appear when the cursor hovers in the vicinity of that point?
It seems none of the other answers here actually answer the question. So here is a code that uses a scatter and shows an annotation upon hovering over the scatter points.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
x = np.random.rand(15)
y = np.random.rand(15)
names = np.array(list("ABCDEFGHIJKLMNO"))
c = np.random.randint(1,5,size=15)
norm = plt.Normalize(1,4)
cmap = plt.cm.RdYlGn
fig,ax = plt.subplots()
sc = plt.scatter(x,y,c=c, s=100, cmap=cmap, norm=norm)
annot = ax.annotate("", xy=(0,0), xytext=(20,20),textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"),
arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)
def update_annot(ind):
pos = sc.get_offsets()[ind["ind"][0]]
annot.xy = pos
text = "{}, {}".format(" ".join(list(map(str,ind["ind"]))),
" ".join([names[n] for n in ind["ind"]]))
annot.set_text(text)
annot.get_bbox_patch().set_facecolor(cmap(norm(c[ind["ind"][0]])))
annot.get_bbox_patch().set_alpha(0.4)
def hover(event):
vis = annot.get_visible()
if event.inaxes == ax:
cont, ind = sc.contains(event)
if cont:
update_annot(ind)
annot.set_visible(True)
fig.canvas.draw_idle()
else:
if vis:
annot.set_visible(False)
fig.canvas.draw_idle()
fig.canvas.mpl_connect("motion_notify_event", hover)
plt.show()
Because people also want to use this solution for a line plot instead of a scatter, the following would be the same solution for plot (which works slightly differently).
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
x = np.sort(np.random.rand(15))
y = np.sort(np.random.rand(15))
names = np.array(list("ABCDEFGHIJKLMNO"))
norm = plt.Normalize(1,4)
cmap = plt.cm.RdYlGn
fig,ax = plt.subplots()
line, = plt.plot(x,y, marker="o")
annot = ax.annotate("", xy=(0,0), xytext=(-20,20),textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"),
arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)
def update_annot(ind):
x,y = line.get_data()
annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])
text = "{}, {}".format(" ".join(list(map(str,ind["ind"]))),
" ".join([names[n] for n in ind["ind"]]))
annot.set_text(text)
annot.get_bbox_patch().set_alpha(0.4)
def hover(event):
vis = annot.get_visible()
if event.inaxes == ax:
cont, ind = line.contains(event)
if cont:
update_annot(ind)
annot.set_visible(True)
fig.canvas.draw_idle()
else:
if vis:
annot.set_visible(False)
fig.canvas.draw_idle()
fig.canvas.mpl_connect("motion_notify_event", hover)
plt.show()
In case someone is looking for a solution for bar plots, please refer to e.g. this answer.
回答 1
当悬停一行而不需要单击它时,此解决方案有效:
import matplotlib.pyplot as plt
# Need to create as global variable so our callback(on_plot_hover) can access
fig = plt.figure()
plot = fig.add_subplot(111)# create some curvesfor i in range(4):# Giving unique ids to each data member
plot.plot([i*1,i*2,i*3,i*4],
gid=i)def on_plot_hover(event):# Iterating over each data member plottedfor curve in plot.get_lines():# Searching which data member corresponds to current mouse positionif curve.contains(event)[0]:print"over %s"% curve.get_gid()
fig.canvas.mpl_connect('motion_notify_event', on_plot_hover)
plt.show()
This solution works when hovering a line without the need to click it:
import matplotlib.pyplot as plt
# Need to create as global variable so our callback(on_plot_hover) can access
fig = plt.figure()
plot = fig.add_subplot(111)
# create some curves
for i in range(4):
# Giving unique ids to each data member
plot.plot(
[i*1,i*2,i*3,i*4],
gid=i)
def on_plot_hover(event):
# Iterating over each data member plotted
for curve in plot.get_lines():
# Searching which data member corresponds to current mouse position
if curve.contains(event)[0]:
print "over %s" % curve.get_gid()
fig.canvas.mpl_connect('motion_notify_event', on_plot_hover)
plt.show()
from matplotlib.pyplot import figure, show
import numpy as npy
from numpy.random import rand
if 1: # picking on a scatter plot (matplotlib.collections.RegularPolyCollection)
x, y, c, s = rand(4, 100)
def onpick3(event):
ind = event.ind
print('onpick3 scatter:', ind, npy.take(x, ind), npy.take(y, ind))
fig = figure()
ax1 = fig.add_subplot(111)
col = ax1.scatter(x, y, 100*s, c, picker=True)
#fig.savefig('pscoll.eps')
fig.canvas.mpl_connect('pick_event', onpick3)
show()
import matplotlib.pyplot as plt
import numpy as np
import mplcursors
data = np.outer(range(10), range(1,5))
fig, ax = plt.subplots()
lines = ax.plot(data)
ax.set_title("Click somewhere on a line.\nRight-click to deselect.\n""Annotations can be dragged.")
mplcursors.cursor(lines)# or just mplcursors.cursor()
plt.show()
mplcursors worked for me. mplcursors provides clickable annotation for matplotlib. It is heavily inspired from mpldatacursor (https://github.com/joferkington/mpldatacursor), with a much simplified API
import matplotlib.pyplot as plt
import numpy as np
import mplcursors
data = np.outer(range(10), range(1, 5))
fig, ax = plt.subplots()
lines = ax.plot(data)
ax.set_title("Click somewhere on a line.\nRight-click to deselect.\n"
"Annotations can be dragged.")
mplcursors.cursor(lines) # or just mplcursors.cursor()
plt.show()
The other answers did not address my need for properly showing tooltips in a recent version of Jupyter inline matplotlib figure. This one works though:
import matplotlib.pyplot as plt
import numpy as np
import mplcursors
np.random.seed(42)
fig, ax = plt.subplots()
ax.scatter(*np.random.random((2, 26)))
ax.set_title("Mouse over a point")
crs = mplcursors.cursor(ax,hover=True)
crs.connect("add", lambda sel: sel.annotation.set_text(
'Point {},{}'.format(sel.target[0], sel.target[1])))
plt.show()
Leading to something like the following picture when going over a point with mouse:
回答 7
如果使用jupyter笔记本,我的解决方案很简单:
%pylab
import matplotlib.pyplot as plt
import mplcursors
plt.plot(...)
mplcursors.cursor(hover=True)
plt.show()
import matplotlib.pyplot as plt
def update_annot(ind, line, annot, ydata):
x, y = line.get_data()
annot.xy =(x[ind["ind"][0]], y[ind["ind"][0]])# Get x and y values, then format them to be displayed
x_values =" ".join(list(map(str, ind["ind"])))
y_values =" ".join(str(ydata[n])for n in ind["ind"])
text ="{}, {}".format(x_values, y_values)
annot.set_text(text)
annot.get_bbox_patch().set_alpha(0.4)def hover(event, line_info):
line, annot, ydata = line_info
vis = annot.get_visible()if event.inaxes == ax:# Draw annotations if cursor in right position
cont, ind = line.contains(event)if cont:
update_annot(ind, line, annot, ydata)
annot.set_visible(True)
fig.canvas.draw_idle()else:# Don't draw annotationsif vis:
annot.set_visible(False)
fig.canvas.draw_idle()def plot_line(x, y):
line,= plt.plot(x, y, marker="o")# Annotation style may be changed here
annot = ax.annotate("", xy=(0,0), xytext=(-20,20), textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"),
arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)
line_info =[line, annot, y]
fig.canvas.mpl_connect("motion_notify_event",lambda event: hover(event, line_info))# Your data values to plot
x1 = range(21)
y1 = range(0,21)
x2 = range(21)
y2 = range(0,42,2)# Plot line graphs
fig, ax = plt.subplots()
plot_line(x1, y1)
plot_line(x2, y2)
plt.show()
REQUIRED DEPENDENCIES AND EXTENSIONS
numpy: yes [not found. pip may install it below.]
dateutil: yes [dateutil was not found.Itis required for date
axis support. pip/easy_install may attempt to
install it after matplotlib.]
tornado: yes [tornado was not found.Itis required for the
WebAgg backend. pip/easy_install may attempt to
install it after matplotlib.]
pyparsing: yes [pyparsing was not found.Itis required for
mathtext support. pip/easy_install may attempt to
install it after matplotlib.]
pycxx: yes [Couldn't import. Using local copy.]
libagg: yes [pkg-config information for 'libagg' could not
be found. Using local copy.]
freetype: no [pkg-config information for 'freetype2' could
not be found.]
…
The following required packages can not be built:* freetype
When performing pip install -r requirements.txt, I get the following error during the stage where it is installing matplotlib:
REQUIRED DEPENDENCIES AND EXTENSIONS
numpy: yes [not found. pip may install it below.]
dateutil: yes [dateutil was not found. It is required for date
axis support. pip/easy_install may attempt to
install it after matplotlib.]
tornado: yes [tornado was not found. It is required for the
WebAgg backend. pip/easy_install may attempt to
install it after matplotlib.]
pyparsing: yes [pyparsing was not found. It is required for
mathtext support. pip/easy_install may attempt to
install it after matplotlib.]
pycxx: yes [Couldn't import. Using local copy.]
libagg: yes [pkg-config information for 'libagg' could not
be found. Using local copy.]
freetype: no [pkg-config information for 'freetype2' could
not be found.]
…
The following required packages can not be built:
* freetype
Shouldn’t pip install -r requirements.txt also install freetype? How should freetype be installed in Ubuntu 12.04 so it works with matplotlib?
I had the same issue with Python 3.6 on Windows, but then I switched to Python 3.5.2 and everything works fine.
回答 8
这个命令sudo apt-get install libfreetype6-dev对我来说在Ubuntu 16.04上失败了, The following packages have unmet dependencies:
libfreetype6-dev : Depends: libfreetype6 (= 2.6.1-0.1ubuntu2) but
2.6.1-0.1ubuntu2.3 is to be installed
This command sudo apt-get install libfreetype6-dev failed for me on ubuntu 16.04, The following packages have unmet dependencies:
libfreetype6-dev : Depends: libfreetype6 (= 2.6.1-0.1ubuntu2) but
2.6.1-0.1ubuntu2.3 is to be installed
So I downloaded installed freetype from the source, credit to this guide
$ tar -xvjf freetype-x.y.tar.bz2 # extract the downloaded version file
$ cd freetype-x.y/
$ ./configure
$ make
$ sudo make install
switched to virtualenv and pip install matplotlib and everything is working.
from matplotlib import pyplot as plt
import numpy as np
x = np.linspace(0,30,30)
y = np.sin(x/6*np.pi)
error = np.random.normal(0.1,0.02, size=y.shape)
y += np.random.normal(0,0.1, size=y.shape)
plt.plot(x, y,'k-')
plt.fill_between(x, y-error, y+error)
plt.show()
Ignoring the smooth interpolation between points in your example graph (that would require doing some manual interpolation, or just have a higher resolution of your data), you can use pyplot.fill_between():
from matplotlib import pyplot as plt
import numpy as np
x = np.linspace(0, 30, 30)
y = np.sin(x/6*np.pi)
error = np.random.normal(0.1, 0.02, size=y.shape)
y += np.random.normal(0, 0.1, size=y.shape)
plt.plot(x, y, 'k-')
plt.fill_between(x, y-error, y+error)
plt.show()
and now I would like to give this plot common x-axis labels and y-axis labels. With “common”, I mean that there should be one big x-axis label below the whole grid of subplots, and one big y-axis label to the right. I can’t find anything about this in the documentation for plt.subplots, and my googlings suggest that I need to make a big plt.subplot(111) to start with – but how do I then put my 5*2 subplots into that using plt.subplots?
Since I consider it relevant and elegant enough (no need to specify coordinates to place text), I copy (with a slight adaptation) an answer to another related question.
import matplotlib.pyplot as plt
fig, axes = plt.subplots(5, 2, sharex=True, sharey=True, figsize=(6,15))
# add a big axis, hide frame
fig.add_subplot(111, frameon=False)
# hide tick and tick label of the big axis
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.xlabel("common X")
plt.ylabel("common Y")
This results in the following (with matplotlib version 2.2.0):
回答 2
如果没有sharex=True, sharey=True得到:
有了它,你应该变得更好:
fig, axes2d = plt.subplots(nrows=3, ncols=3,
sharex=True, sharey=True,
figsize=(6,6))for i, row in enumerate(axes2d):for j, cell in enumerate(row):
cell.imshow(np.random.rand(32,32))
plt.tight_layout()
但是,如果要添加其他标签,则应仅将其添加到边缘图中:
fig, axes2d = plt.subplots(nrows=3, ncols=3,
sharex=True, sharey=True,
figsize=(6,6))for i, row in enumerate(axes2d):for j, cell in enumerate(row):
cell.imshow(np.random.rand(32,32))if i == len(axes2d)-1:
cell.set_xlabel("noise column: {0:d}".format(j +1))if j ==0:
cell.set_ylabel("noise row: {0:d}".format(i +1))
plt.tight_layout()
fig, axes2d = plt.subplots(nrows=3, ncols=3,
sharex=True, sharey=True,
figsize=(6,6))
for i, row in enumerate(axes2d):
for j, cell in enumerate(row):
cell.imshow(np.random.rand(32,32))
plt.tight_layout()
But if you want to add additional labels, you should add them only to the edge plots:
fig, axes2d = plt.subplots(nrows=3, ncols=3,
sharex=True, sharey=True,
figsize=(6,6))
for i, row in enumerate(axes2d):
for j, cell in enumerate(row):
cell.imshow(np.random.rand(32,32))
if i == len(axes2d) - 1:
cell.set_xlabel("noise column: {0:d}".format(j + 1))
if j == 0:
cell.set_ylabel("noise row: {0:d}".format(i + 1))
plt.tight_layout()
Adding label for each plot would spoil it (maybe there is a way to automatically detect repeated labels, but I am not aware of one).
you used returns a tuple consisting of the figure and a list of the axes instances, it is already sufficient to do something like (mind that I’ve changed fig,axto fig,axes):
fig,axes = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)
for ax in axes:
ax.set_xlabel('Common x-label')
ax.set_ylabel('Common y-label')
If you happen to want to change some details on a specific subplot, you can access it via axes[i] where i iterates over your subplots.
It might also be very helpful to include a
fig.tight_layout()
at the end of the file, before the plt.show(), in order to avoid overlapping labels.
It will look better if you reserve space for the common labels by making invisible labels for the subplot in the bottom left corner. It is also good to pass in the fontsize from rcParams. This way, the common labels will change size with your rc setup, and the axes will also be adjusted to leave space for the common labels.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
# Create outer and inner grid
outerGrid = gridspec.GridSpec(2,3, width_ratios=[1,1,1], height_ratios=[1,1])
somePlot = gridspec.GridSpecFromSubplotSpec(2,1,
subplot_spec=outerGrid[3], height_ratios=[1,3], hspace =0)# Add two partial plots
partA = plt.subplot(somePlot[0])
partB = plt.subplot(somePlot[1])# No x-ticks for the upper plot
plt.setp(partA.get_xticklabels(), visible=False)# The center is (height(top)-height(bottom))/(2*height(top))# Simplified to 0.5 - height(bottom)/(2*height(top))
mid =0.5-somePlot.get_height_ratios()[1]/(2.*somePlot.get_height_ratios()[0])# Place the y-label
partA.set_ylabel('shared label', y = mid)
plt.show()
I ran into a similar problem while plotting a grid of graphs. The graphs consisted of two parts (top and bottom). The y-label was supposed to be centered over both parts.
I did not want to use a solution that depends on knowing the position in the outer figure (like fig.text()), so I manipulated the y-position of the set_ylabel() function. It is usually 0.5, the middle of the plot it is added to. As the padding between the parts (hspace) in my code was zero, I could calculate the middle of the two parts relative to the upper part.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
# Create outer and inner grid
outerGrid = gridspec.GridSpec(2, 3, width_ratios=[1,1,1], height_ratios=[1,1])
somePlot = gridspec.GridSpecFromSubplotSpec(2, 1,
subplot_spec=outerGrid[3], height_ratios=[1,3], hspace = 0)
# Add two partial plots
partA = plt.subplot(somePlot[0])
partB = plt.subplot(somePlot[1])
# No x-ticks for the upper plot
plt.setp(partA.get_xticklabels(), visible=False)
# The center is (height(top)-height(bottom))/(2*height(top))
# Simplified to 0.5 - height(bottom)/(2*height(top))
mid = 0.5-somePlot.get_height_ratios()[1]/(2.*somePlot.get_height_ratios()[0])
# Place the y-label
partA.set_ylabel('shared label', y = mid)
plt.show()
This feature is now part of the proplot matplotlib package that I recently released on pypi. By default, when you make figures, the labels are “shared” between axes.
Original answer:
I discovered a more robust method:
If you know the bottom and top kwargs that went into a GridSpec initialization, or you otherwise know the edges positions of your axes in Figure coordinates, you can also specify the ylabel position in Figure coordinates with some fancy “transform” magic. For example:
import matplotlib.transforms as mtransforms
bottom, top = .1, .9
f, a = plt.subplots(nrows=2, ncols=1, bottom=bottom, top=top)
avepos = (bottom+top)/2
a[0].yaxis.label.set_transform(mtransforms.blended_transform_factory(
mtransforms.IdentityTransform(), f.transFigure # specify x, y transform
)) # changed from default blend (IdentityTransform(), a[0].transAxes)
a[0].yaxis.label.set_position((0, avepos))
a[0].set_ylabel('Hello, world!')
…and you should see that the label still appropriately adjusts left-right to keep from overlapping with ticklabels, just like normal — but now it will adjust to be always exactly between the desired subplots.
Furthermore, if you don’t even use set_position, the ylabel will show up by default exactly halfway up the figure. I’m guessing this is because when the label is finally drawn, matplotlib uses 0.5 for the y-coordinate without checking whether the underlying coordinate transform has changed.
and the data is presented fine, but I am having the problem that the figure title is overlapping with the axes labels on the secondary x axis so that it’s barely legible (I wanted to post a picture example here, but I don’t have a high enough rep yet).
I’d like to know if there’s a straightforward way to just shift the title directly up a few tens of pixels, so that the chart looks prettier.
I am making a scatter plot in matplotlib and need to change the background of the actual plot to black. I know how to change the face color of the plot using:
You used the stateful API (if you’re doing anything more than a few lines, and especially if you have multiple plots, the object-oriented methods above make life easier because you can refer to specific figures, plot on certain axes, and customize either)
Matplotlib recognizes the following formats to specify a color:
an RGB or RGBA tuple of float values in [0, 1] (e.g., (0.1, 0.2, 0.5) or (0.1, 0.2, 0.5, 0.3));
a hex RGB or RGBA string (e.g., '#0F0F0F' or '#0F0F0F0F');
a string representation of a float value in [0, 1] inclusive for gray level (e.g., '0.5');
one of {'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'};
a X11/CSS4 color name;
a name from the xkcd color survey; prefixed with 'xkcd:' (e.g., 'xkcd:sky blue');
one of {'tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:gray', 'tab:olive', 'tab:cyan'} which are the Tableau Colors from the ‘T10’ categorical palette (which is the default color cycle);
a “CN” color spec, i.e. ‘C’ followed by a single digit, which is an index into the default property cycle (matplotlib.rcParams['axes.prop_cycle']); the indexing occurs at artist creation time and defaults to black if the cycle does not include color.
All string specifications of color, other than “CN”, are case-insensitive.
One method is to manually set the default for the axis background color within your script (see Customizing matplotlib):
import matplotlib.pyplot as plt
plt.rcParams['axes.facecolor'] = 'black'
This is in contrast to Nick T’s method which changes the background color for a specific axes object. Resetting the defaults is useful if you’re making multiple different plots with similar styles and don’t want to keep changing different axes objects.
One suggestion in other answers is to use ax.set_axis_bgcolor("red"). This however is deprecated, and doesn’t work on MatPlotLib >= v2.0.
There is also the suggestion to use ax.patch.set_facecolor("red") (works on both MatPlotLib v1.5 & v2.2). While this works fine, an even easier solution for v2.0+ is to use