I am having a major setback on this question on a while now...
import numpy as np
import matplotlib.pyplot as plt
plt.ion()
fig = plt.figure(1)
ax = fig.add_subplot(111)
ax.set_title("linear realtime")
line, = ax.plot([],[])
i = 0
while ( i < 1000 ):
#EDIT:
# this is just sample data, but I would eventually like to set data
# where it can be floating numbers...
line.set_data(i,i)
fig.canvas.draw()
i += 1
I am trying to draw a linear line in real time but I am unable to come up with the result. Thanks in advance. So far, I have a figure coming up but nothing is being drawn on the canvas.
EDIT:
Interesting.... I am now able to plot the dots on the line but now, I am unable to show their connectivity between each point... I also noticed that if you removed ko- when it is being plotted... nothing appears, does anybody know why?
import numpy as n
import pylab as p
import time
x=0
y=0
p.ion()
fig=p.figure(1)
ax=fig.add_subplot(111)
ax.set_xlim(0,10)
ax.set_ylim(0,10)
line,=ax.plot(x,y,'ko-')
for i in range(10):
x = i
y = i
line.set_data(x,y)
p.draw()
add a p.pause(.001) in your loop. You need to allow time for the gui event loops to trigger and update the display.
This is related to issue #1646.
The other issue you have is that when you do set_data it replaces the data that is plotted with the x and y passed in, not append to the data that is already there. (To see this clearly use p.pause(1)) When you remove 'ko-', which defaults to no marker with a line connecting points you are plotting a single point, hence nothing shows up.
I think you intended to write this:
x=0
y=0
fig=plt.figure(1)
ax=fig.add_subplot(111)
ax.set_xlim(0,10)
ax.set_ylim(0,10)
line,=ax.plot(x,y,'ko-')
for i in range(10):
x = np.concatenate((line.get_xdata(),[i]))
y = np.concatenate((line.get_ydata(),[i]))
line.set_data(x,y)
plt.pause(1)
Related
I'm trying to set xlimits and keep the margins.
In a simplified code, the dataset contains 50 values. When plotting the whole data set, it is fine. However, I only want to plot values 20-40. The plot starts and ends without having any margins.
How do I plot values 20-40 but keep the margins?
Online I found to ways to play with the margin/padding
1) plt.tight_layout(pad=1.08, h_pad=None, w_pad=None, rect=None)
2) ax1.margins(0.05)
Both, however, do not seem to work when using xlimits.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(1, 200, 50)
y = np.random.random(len(x))
fig_1 = plt.figure(figsize=(8, 4))
ax1 = plt.subplot(1,1,1)
ax1.plot(x, y)
ax1.set_xlim(x[19], x[40])
# ax1.plot(x[19:40], y[19:40])
# would create exactly the plot I want. But it is not the solution I am looking for.
# I cannot change/slice the data. I want to change the figure.
As shown in the figure,
How can I plot a line that have different colors based on a specific value of x ?
The simplest solution here may be to slice your data at the corresponding index of x_lim found by np.where :
from matplotlib import pyplot as plt
import numpy as np
x = np.linspace(0,2*np.pi,100)
y = np.cos(x)*np.exp(-x/2)
# specify your x limitation
x_lim = np.pi
# find the first corresponding idx where the condition x>=x_lim hold
x_lim_idx = np.where(x>=x_lim)[0][0]
# plot sliced data
plt.plot(x[:x_lim_idx],y[:x_lim_idx],'r')
plt.plot(x[x_lim_idx:],y[x_lim_idx:],'b')
which gives for x_lim = np.pi :
And if the remaining gap between the lines bothers you, for small x discretization for instance, you can still close it by making the two slices overlap.
I'd like to make a streamplot with lines that don't stop when they get too close together. I'd rather each streamline be calculated in both directions until it hits the edge of the window. The result is there'd be some areas where they'd all jumble up. But that's what I want.
I there anyway to do this in matplotlib? If not, is there another tool I can use for this that could interface with python/numpy?
import numpy as np
import matplotlib.pyplot as plt
Y,X = np.mgrid[-10:10:.01, -10:10:.01]
U, V = Y**2, X**2
plt.streamplot(X,Y, U,V, density=1)
plt.show(False)
Ok, I've figured out I can get mostly what I want by turning up the density a lot and using custom start points. I'm still interested if there is a better or alternate way to do this.
Here's my solution. Doesn't it look so much better?
import numpy as np
import matplotlib.pyplot as plt
Y,X = np.mgrid[-10:10:.01, -10:10:.01]
y,x = Y[:,0], X[0,:]
U, V = Y**2, X**2
stream_points = np.array(zip(np.arange(-9,9,.5), -np.arange(-9,9,.5)))
plt.streamplot(x,y, U,V, start_points=stream_points, density=35)
plt.show(False)
Edit: By the way, there seems to be some bug in streamplot such that start_points keyword only works if you use 1d arrays for the grid data. See Python Matplotlib Streamplot providing start points
As of Matplotlib version 3.6.0, an optional parameter broken_streamlines has been added for disabling streamline breaks.
Adding it to your snippet produces the following result:
import numpy as np
import matplotlib.pyplot as plt
Y,X = np.mgrid[-10:10:.01, -10:10:.01]
U, V = Y**2, X**2
plt.streamplot(X,Y, U,V, density=1, broken_streamlines=False)
plt.show(False)
Note
This parameter just extends the streamlines which were originally drawn (as in the question). This means that the streamlines in the modified plot above are much more uneven than the result obtained in the other answer, with custom start_points. The density of streamlines on any stream plot does not represent the magnitude of U or V at that point, only their direction. See the documentation for the density parameter of matplotlib.pyplot.streamplot for more details on how streamline start points are chosen by default, when they aren't specified by the optional start_points parameter.
For accurate streamline density, consider using matplotlib.pyplot.contour, but be aware that contour does not show arrows.
Choosing start points automatically
It may not always be easy to choose a set of good starting points automatically. However, if you know the streamfunction corresponding to the flow you wish to plot you can use matplotlib.pyplot.contour to produce a contour plot (which can be hidden from the output), and then extract a suitable starting point from each of the plotted contours.
In the following example, psi_expression is the streamfunction corresponding to the flow. When modifying this example for your own needs, make sure to update both the line defining psi_expression, as well as the one defining U and V. Ensure these both correspond to the same flow.
The density of the streamlines can be altered by changing contour_levels. Here, the contours are uniformly distributed.
import numpy as np
import matplotlib.pyplot as plt
import sympy as sy
x, y = sy.symbols("x y")
psi_expression = x**3 - y**3
psi_function = sy.lambdify((x, y), psi_expression)
Y, X = np.mgrid[-10:10:0.01, -10:10:0.01]
psi_evaluated = psi_function(X, Y)
U, V = Y**2, X**2
contour_levels = np.linspace(np.amin(psi_evaluated), np.amax(psi_evaluated), 30)
# Draw a temporary contour plot.
temp_figure = plt.figure()
contour_plot = plt.contour(X, Y, psi_evaluated, contour_levels)
plt.close(temp_figure)
points_list = []
# Iterate over each contour.
for collection in contour_plot.collections:
# Iterate over each segment in this contour.
for path in collection.get_paths():
middle_point = path.vertices[len(path.vertices) // 2]
points_list.append(middle_point)
# Reshape python list into numpy array of coords.
stream_points = np.reshape(np.array(points_list), (-1, 2))
plt.streamplot(X, Y, U, V, density=1, start_points=stream_points, broken_streamlines=False)
plt.show(False)
Using 1.5.1 in Python 2.7.
I'm creating a figure, adding an axes object to it, creating a canvas, and putting it into a window. To draw a simple graph, I set the X and Y limits in the axes object, and then call the plot member function with a numpy arange of values and an array of y values of the same length, along with a few formatting options.
What I get is a nice graph of my data, but it is drawn as a closed curve, meaning that there is a diagonal line leading from the end of my graph back to the beginning.
Why would it do this? I can see the occasional utility of an option that does this, when the X values aren't monotonically increasing (say, to draw a polygon), but it hardly seems like a reasonable default. I don't see any axes attribute that would affect this, or any plot parameter. Does anyone know how to make it not wrap around like this?
EDIT: here is some sample code. It assumes PyGTK as the GUI environment:
import numpy
import gtk
import matplotlib
from matplotlib.figure import Figure
from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas
class junk:
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect('destroy', self.destroy)
self.window.set_title('junk')
self.window.resize(400, 400)
self.figure = Figure()
self.axes = self.figure.add_axes((0, 0, 1, 1))
self.canvas = FigureCanvas(self.figure)
self.canvas.show()
self.window.add(self.canvas)
self.axes.set_xlim(-10, 12)
self.axes.set_ylim(-1, 122)
x = numpy.arange(-9, 12)
self.axes.plot(x, x * x, linestyle = 'solid')
self.canvas.draw()
self.window.show_all()
def destroy(self, widget, data = None):
gtk.main_quit()
def main(self):
gtk.main()
if __name__ == '__main__':
app = junk()
app.main()
This displays an off-center parabola, and the result looks like this:
Now change the lower Y limit from -1 to 1, so that it clips the bottom a little, and the result looks like this:
This shows that if more than one path is needed to draw the graph, each one has the spurious wraparound.
I'm doing this on Windows, but I had this same problem a couple years ago running on a Gumstix SOM running Linux.
I can not reproduce your issue with the given code
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
x = np.arange(-9, 12)
ax.plot(x, x*x)
plt.show()
A line is drawn between the points in the order you pass them in. This is the behavior so you can plot things with are not strict functions of x.
BrenBarn identified the solution in the comment to the original post: use the GTKAgg backend instead of the GTK backend. Thanks.
I have a list to which I append Axes3D plots. Like this:
self.myList.append(self.axes.plot(xValues,
yValues,
zValues,
picker=self.line_picker)[0])
When that line of code runs, the instance returned by the plot() function is stored in the list AND the line is automatically plotted, which is what I want. This code runs on program startup and draws a variable number of lines.
Now what I need to do is this:
When the user checks a checkbox, I want to REPLACE the data that is currently plotted with another set of data. Then, when the user unchecks the checkbox, I want the initial data to be plotted again.
I have no problem with clearing the initial data; I simply do:
self.axes.clear()
self.canvas.draw()
self.axes.mouse_init()
and now I have a blank 3D graph.
How can I re-plot the same data once it is cleared? Can I somehow use the plot instances stored in the list and re-plot them?
My ultimate question is, do I have to re-plot the original plot using the raw data like I did the first time, or can I somehow hide/disable the initial axes and then simply restore it?
Probably the easiest solution is to keep a reference of the items and simply toggle the specific artist's visible attribute:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
plt.ion()
ax = plt.axes(projection='3d')
n = 3
xs = np.random.randint(23, 32, n)
ys = np.random.randint(0, 100, n)
zs = np.random.randint(0, 10, n)
scatter = ax.scatter(xs, ys, zs=zs)
plt.draw()
scatter.set_visible(False)
plt.draw()
scatter.set_visible(True)
plt.draw()