I am working on a code to visualize slices from a volume. I have no problem when I have to visualize only one volume as shown on the first code.
#Code working properly
import numpy as np
import matplotlib.pyplot as plt
from skimage.morphology import ball
plt.ion()
plt.show()
sphere = ball(50)
for i in range(len(sphere[0,0])):
plt.clf()
plt.title(i)
plt.imshow(sphere[:,:,i],cmap='gray')
plt.axis('off')
plt.draw()
plt.pause(0.01)
I am having trouble when I want to create a subplot and visualize more than one image simultaneously. With this code I’m able to visualize the volume but it takes too long, and it lags a lot. I have tried clearing the axes before each iteration, but I couldn’t make it work.
This is where my current attempt is at:
#Code that is not working properly
import numpy as np
import matplotlib.pyplot as plt
from skimage.morphology import ball
sphere = ball(50)
plt.ion()
plt.show()
fig, grilla = plt.subplots(1,2, figsize = (20,10))
for i in range(len(sphere[0,0])):
grilla[0].imshow(sphere[:,:,i], cmap = 'gray')
grilla[0].axis('off')
grilla[0].set_title('Slice' +str(i))
grilla[1].imshow(sphere[:,:,i], cmap = 'gray')
grilla[1].axis('off')
grilla[1].set_title('Slice' +str(i))
plt.draw()
plt.pause(0.01)
Related
I'm trying to have my matplotlib plot update in real-time as data is added to a CSV file. The plot is of a small geographic location, axes given by longitude and latitude. This is what I have so far:
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
df = pd.read_csv("cayugacoords.txt")
BoundaryBox = [-76.5119, -76.5013, 42.4596, 42.4642]
ruh_m = plt.imread('map.png')
fig, ax = plt.subplots(figsize=(8, 7))
ax.scatter(df.longitude, df.latitude, zorder=1, alpha=1, c='r', s=10)
ax.set_title('Cayuga Lake Shore')
ax.set_xlim(BoundaryBox[0], BoundaryBox[1])
ax.set_ylim(BoundaryBox[2], BoundaryBox[3])
ax.imshow(ruh_m, zorder=0, extent=BoundaryBox, aspect='equal')
plt.show()
And this is what shows when I run the code (the three points on the bottom left are already in the CSV file):
Current plot
And here's the background image on its own: Cayuga Lake
I want the map to be regularly updated as new coordinates are added to the CSV file. How can this be done? I've looked into animation tools but I'm having trouble retaining the background image of the map while updating the plot. For reference, the CSV file "cayugacoords.txt" looks like this:
longitude,latitude
-76.51,42.46
-76.511,42.46
-76.5105,42.46
Thank you!
An alternative solution which updates only the points on the background image is provided by using ax.collections = [] which clears ALL lines plotted on the image. For the sake of demonstration I plot each coordinate per frame.
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
df = pd.read_csv("cayugacoords.txt")
BoundaryBox = [-76.5119, -76.5013, 42.4596, 42.4642]
ruh_m = plt.imread('map.png')
fig, ax = plt.subplots(figsize=(8, 7))
ax.set_title('Cayuga Lake Shore')
ax.set_xlim(BoundaryBox[0], BoundaryBox[1])
ax.set_ylim(BoundaryBox[2], BoundaryBox[3])
ax.imshow(ruh_m, zorder=0, extent=BoundaryBox, aspect='equal')
def animate(nframe):
ax.collections = []
points = ax.scatter(df.longitude[nframe], df.latitude[nframe], zorder=1,
alpha=1, c='r', s=10)
return
anim = animation.FuncAnimation(fig, animate, frames=3)
This code worked for me. It seems quite hacky but it works. You can adjust the time.sleep to your liking.
from matplotlib import pyplot as plt
from IPython.display import clear_output
import pandas as pd
import numpy as np
import time
%matplotlib inline
ruh_m = plt.imread('map.png')
BoundaryBox = [-76.5119, -76.5013, 42.4596, 42.4642]
while True:
clear_output(wait=True)
df = pd.read_csv("cayugacoords.txt")
fig, ax = plt.subplots(figsize=(10, 10))
ax.scatter(df.longitude, df.latitude, zorder=1, alpha=1, c='r', s=10)
ax.set_title('Cayuga Lake Shore')
ax.set_xlim(BoundaryBox[0], BoundaryBox[1])
ax.set_ylim(BoundaryBox[2], BoundaryBox[3])
ax.imshow(ruh_m, zorder=0, extent=BoundaryBox, aspect='equal')
plt.show()
time.sleep(1E-3)
The texts on the right on this pyplot graph are clipped, how can I expand the plot area without changing the x-axis?
Minimal example code (similar to but not identical to example image)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mp
n40=146-1.07*40
n90=146-1.07*90
ageAxis =np.array([10, 40, 90])
Normal=np.array([n40, n40, n90])
plt.plot(ageAxis,Normal)
plt.text(90.2,50,'long text here that will be clipped')
ax = plt.gca()
ax.set_ylim([0,165])
ax.set_xlim([0,90])
fig= plt.gcf()
# set size fig.set_size_inches(20, 10.5)
plt.show()
It seems that it can be done with a combination of set_size_inches and subplots_adjust
Not elegant, I think, but it works:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mp
n40=146-1.07*40
n90=146-1.07*90
ageAxis =np.array([10, 40, 90])
Normal=np.array([n40, n40, n90])
plt.plot(ageAxis,Normal)
plt.text(90.2,50,'long text here that will be clipped')
ax = plt.gca()
ax.set_ylim([0,165])
ax.set_xlim([0,90])
fig= plt.gcf()
fig.set_size_inches(10, 5.5) # set a suitable size
plt.subplots_adjust(right=0.75) # adjust plot area
plt.show()
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 !
everyone,
I have problem when I tried to adjust colorbar to the same height with figure. I know little about the intrinsic mechanism of data visualization, or axis, fig or something like that. my code is following, sorry for unloading images,
For Figure(1), notice that input data is square, i.e., 51 by 51. The figure is satisfying.
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
plt.cla()
plt.clf()
fig1 = plt.figure(1)
ax0 = plt.subplot()
im0 = ax0.imshow(np.arange(51*51).reshape((51,51)), cmap="hsv")
divider0 = make_axes_locatable(ax0)
ax_cb0 = divider0.append_axes("right", size="2%", pad=0.05)
fig1.add_axes(ax_cb0)
plt.colorbar(im0, cax=ax_cb0)
plt.savefig("tmp0.png", bbox_inches="tight")
For figure (2), the code is following, notice that now the input data is 51 by 501, the output is not satisfying,
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
plt.cla()
plt.clf()
fig2 = plt.figure(2)
ax1 = plt.subplot()
im1 = ax1.imshow(np.arange(51*501).reshape((51,501)), cmap="hsv")
divider1 = make_axes_locatable(ax1)
ax_cb1 = divider1.append_axes("right", size="2%", pad=-4)
fig2.add_axes(ax_cb1)
plt.colorbar(im1, cax=ax_cb1)
ax1.set_aspect(4)
plt.savefig("tmp1.png", bbox_inches="tight")
but still, we can make it better by manually adjusting pad parameter in this line
ax_cb0 = divider0.append_axes("right", size="2%", pad=0.05)
but which is absolutely not the recommended way, COULD anyone know the smart way of doing it or smart way of estimating the value of pad parameter? Thanks in advance.
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()