I'm really confused here; the same code in Python and in IPython Notebook produces two different PNG files with savefig:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(5,4))
ax = fig.add_subplot(1,1,1)
abc = np.random.uniform(size=(50000,3))
print abc.shape
x = (2*abc[:,0]-abc[:,1]-abc[:,2])/3.0
y = (abc[:,1]-abc[:,2])/np.sqrt(3)
ax.plot(x,y,'.',markersize=0.25)
ax.set_aspect('equal')
ax.set_xlabel('x')
ax.set_ylabel('y')
with open('/tmp/screenshots/foo.png','wb') as f:
fig.savefig(f, format='png')
IPython Notebook:
Python:
It's the same PC with the same version of Python in both cases. Is there a way to get the image formatting in IPython using both methods? The Python version produces fuzzy dots and looks poor.
Argh -- I figured it out, the dpi parameter gets chosen somehow differently in the two cases, and if I force it to dpi=72 then it looks nice:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(5,4))
ax = fig.add_subplot(1,1,1)
abc = np.random.uniform(size=(50000,3))
print abc.shape
x = (2*abc[:,0]-abc[:,1]-abc[:,2])/3.0
y = (abc[:,1]-abc[:,2])/np.sqrt(3)
ax.plot(x,y,'.',markersize=0.25)
ax.set_aspect('equal')
ax.set_xlabel('x')
ax.set_ylabel('y')
with open('/tmp/screenshots/foo.png','wb') as f:
fig.savefig(f, format='png', dpi=72)
Related
I've tried to find a way to copy a 3D figure in matplotlib but I didn't find a solution which is appropriate in my case.
From these posts
How do I reuse plots in matplotlib?
and
How to combine several matplotlib figures into one figure?
Using fig2._axstack.add(fig2._make_key(ax),ax) as in the code below gives quite the good result but figure 2 is not interactive I can't rotate the figure etc :
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(1)
ax = fig.gca(projection = '3d')
ax.plot([0,1],[0,1],[0,1])
fig2 = plt.figure(2)
fig2._axstack.add(fig2._make_key(ax),ax)
plt.show()
An alternative would be to copy objects from ax to ax2 using a copy method proposed in this post How do I reuse plots in matplotlib? but executing the code below returns RuntimeError: Can not put single artist in more than one figure :
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np, copy
fig = plt.figure(1)
ax = fig.gca(projection = '3d')
ax.plot([0,1],[0,1],[0,1])
fig2 = plt.figure(2)
ax2 = fig2.gca(projection = '3d')
for n in range(len(ax.lines)) :
ax2.add_line(copy.copy(ax.lines[n]))
plt.show()
Those codes are pretty simple but I don't want to copy/paste part of my code for drawing similar figures
Thanks in advance for your reply !
When plotting a colorbar, the top label (I guess this would be called the offset) is mis-centred. This didn't use to happen, I have examples of old code where it was centred above the colorbar, but I have no clue what has changed.
Example:
import numpy as np
import matplotlib.pyplot as plt
z = np.random.random((10,10))
fig, ax = plt.subplots()
im = ax.imshow(z)
cb = fig.colorbar(im)
cb.formatter.set_powerlimits((0, 0))
cb.update_ticks()
plt.show()
Gives this:
As an example of how it used to look (taken from one of my old papers, so
different data etc.)
Using the most recent anaconda python 2.7, on MacOSX, mpl version 1.5.0
Edit: I should also note, tight_layout() does not improve this either, though it is missing from the working example.
You can simply use set_offset_position for the y-axis of the colorbar. Compare:
fig, ax = plt.subplots()
im = ax.imshow(np.random.random((10,10)))
cb = fig.colorbar(im)
cb.formatter.set_powerlimits((0, 0))
cb.ax.yaxis.set_offset_position('right')
cb.update_ticks()
plt.show()
versus
fig, ax = plt.subplots()
im = ax.imshow(np.random.random((10,10)))
cb = fig.colorbar(im)
cb.formatter.set_powerlimits((0, 0))
cb.ax.yaxis.set_offset_position('left')
cb.update_ticks()
plt.show()
All in all, it simply looks like the default has changed from right to left.
Using your above code and matplotlib version 1.4.3 I get the following plot
So this may be a version issue. One possible work around could be to use cb.ax.text()
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
z = np.random.random((10,10))
fig, ax = plt.subplots()
im = ax.imshow(z)
cb = fig.colorbar(im)
cb.ax.text(-0.25, 1, r'$\times$10$^{-1}$', va='bottom', ha='left')
plt.show()
This way you have more control over the centring. The above code gives me the following plot
Note that I use an r at the start of the string so that $\times$ produces the correct symbol.
I have a problem when making graphs using matplotlib,
for some simple graphs the library works fine, for example:
import matplotlib.pyplot as plt
plt.plot([1,2,3,4])
plt.ylabel('some numbers')
plt.show()
but when I use figure module, i get blank figures, like this
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x = np.linspace(0, 10, 200)
y = np.sin(x)
ax.plot(x, y, 'r-', linewidth=2, label=r'$y=\sin(x)$', alpha=0.6)
ax.legend(loc='upper center')
plt.show()
I've tried the same code in a a different python editor or using the shell and it woks fine. I'm using :
Windows,
PyDev v4.2,
python v2.7.10
Python 2.7.9, matplotlib 1.4.0, ipython 2.3.1, macbook pro retina
I am using ipython's interact() with a 3D plot in an ipython notebook, but find that the graph updates too slowly when changing a slider control. Here is example code that has this problem when run:
from IPython.html.widgets import *
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import math
%matplotlib inline
def plt3Dsin(angle):
npnts = 100
rotationangle_radians = math.radians(angle)
tab_x = np.linspace(0,3,npnts)
tab_y = np.zeros(npnts)
tab_z = np.sin(2.0*np.pi*tab_x)
yrotate = tab_z * np.sin(rotationangle_radians)
zrotate = tab_z * np.cos(rotationangle_radians)
fig = plt.figure()
ax = Axes3D(fig)
ax.plot(tab_x, yrotate, zrotate)
ax.set_xlim3d([0.0,3.0])
ax.set_ylim3d([-1.0,1.0])
ax.set_zlim3d([-1.0,1.0])
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
interact(plt3Dsin,angle=(0,360,5));
I have tried to separate out the figure and axes creation from actual plotting in the following code, but the first time I change the slider the graph doesn't update and the 2nd time I change it the graph disappears altogether. I assume I'm doing something wrong, but have not been able to figure out what. (The use of globals below is just a quick expedient approach for this simple example code.)
npnts = 100
tab_x = np.linspace(0,3,npnts)
def init_plt3Dsin():
global fig
global ax
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot([], [], [], lw=2)
ax.set_xlim3d([0.0,3.0])
ax.set_ylim3d([-1.0,1.0])
ax.set_zlim3d([-1.0,1.0])
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
def plt3Dsin(angle):
global fig
global ax
rotationangle_radians = math.radians(angle)
tab_y = np.zeros(npnts)
tab_z = np.sin(2.0*np.pi*tab_x)
yrotate = tab_z * np.sin(rotationangle_radians)
zrotate = tab_z * np.cos(rotationangle_radians)
ax.plot(tab_x, yrotate, zrotate)
init_plt3Dsin()
interact(plt3Dsin,angle=(0,360,5));
tcaswell's comment suggesting the use of the nbagg backend offered a good way to address my problem in that it made the first code block run fast enough to be satisfactory.
I am drawing two subplots with Matplotlib, essentially following :
subplot(211); imshow(a); scatter(..., ...)
subplot(212); imshow(b); scatter(..., ...)
Can I draw lines between those two subplots? How would I do that?
The solution from the other answers are suboptimal in many cases (as they would only work if no changes are made to the plot after calculating the points).
A better solution would use the specially designed ConnectionPatch:
import matplotlib.pyplot as plt
from matplotlib.patches import ConnectionPatch
import numpy as np
fig = plt.figure(figsize=(10,5))
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
x,y = np.random.rand(100),np.random.rand(100)
ax1.plot(x,y,'ko')
ax2.plot(x,y,'ko')
i = 10
xy = (x[i],y[i])
con = ConnectionPatch(xyA=xy, xyB=xy, coordsA="data", coordsB="data",
axesA=ax2, axesB=ax1, color="red")
ax2.add_artist(con)
ax1.plot(x[i],y[i],'ro',markersize=10)
ax2.plot(x[i],y[i],'ro',markersize=10)
plt.show()
You could use fig.line. It adds any line to your figure. Figure lines are higher level than axis lines, so you don't need any axis to draw it.
This example marks the same point on the two axes. It's necessary to be careful with the coordinate system, but the transform does all the hard work for you.
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
fig = plt.figure(figsize=(10,5))
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
x,y = np.random.rand(100),np.random.rand(100)
ax1.plot(x,y,'ko')
ax2.plot(x,y,'ko')
i = 10
transFigure = fig.transFigure.inverted()
coord1 = transFigure.transform(ax1.transData.transform([x[i],y[i]]))
coord2 = transFigure.transform(ax2.transData.transform([x[i],y[i]]))
line = matplotlib.lines.Line2D((coord1[0],coord2[0]),(coord1[1],coord2[1]),
transform=fig.transFigure)
fig.lines = line,
ax1.plot(x[i],y[i],'ro',markersize=20)
ax2.plot(x[i],y[i],'ro',markersize=20)
plt.show()
I'm not sure if this is exactly what you are looking for, but a simple trick to plot across subplots.
import matplotlib.pyplot as plt
import numpy as np
ax1=plt.figure(1).add_subplot(211)
ax2=plt.figure(1).add_subplot(212)
x_data=np.linspace(0,10,20)
ax1.plot(x_data, x_data**2,'o')
ax2.plot(x_data, x_data**3, 'o')
ax3 = plt.figure(1).add_subplot(111)
ax3.plot([5,5],[0,1],'--')
ax3.set_xlim([0,10])
ax3.axis("off")
plt.show()