I'm making a plotting app which should, through a tkinter gui, allow the user to create plots to graph spectral data, and modify the plots.
I'm trying to make it so the user can change the limits of the x and y axes after data has been plotted. Looking through the mpl docs, it seems like the obvious solution is to use the set_xlim and set_ylim methods. However, if these methods are invoked after a line is plotted, the line can no longer be seen, and there are no intermediate axis ticks. Through my other widgets, I know the lines are still contained in the lines attribute of the axis object, they just aren't visible.
My question is, is there a way to 'set' the the axes after a line has been plotted, so that the data will adjust to it, i.e be visible after adjusting the axes, and have ticks like it did before being adjusted? I'll show images of the graph to illustrate my situation. The class definitions are rather long, so I'll just show the use of set_xlim and set_ylim
The plot before changing the axis limits:
The plot after changing the x limits:
if all(entry.get() for entry in {self.lxlimEntry, self.rxlimEntry}):
self.master.controller.get_plots()[self.plotVar.get()].axes[0].set_xlim(self.lxlimEntry.get(), self.rxlimEntry.get())
if all(entry.get() for entry in {self.lylimEntry, self.rylimEntry}):
self.master.controller.get_plots()[self.plotVar.get()].axes[0].set_ylim(self.lylimEntry.get(), self.rylimEntry.get())
The Entry widgets are contained in a Toplevel, instantiated by a page of the application (master), and the Entries are where the user inputs the new x and y limits. The controller is the App backend.
Related
I am running a function that runs multiple sub-functions, each calling for an axis in a plot (for example, a 2x2 matplotlib subplot). While the figure is working out, I'd like to reduce some of the padding, notably for the x axis. Is there anything I can do to minimize some space and offer more room in the plots for the data to be seen?
Currently, I am calling plt.tight_layout(pad=0.1, w_pad=0.05, h_pad=0.05) at the end prior to calling plt.show() and plotting; should I opt to use for whenever an axis is established instead? I am also using the labelpad modifier when generated each axis title; however, this is done as part of each sub-function that works on its own axis and tight_layout() is called at the end, so perhaps it is pointless?
Finally, here is what I am able to get with the above padding settings, and I cannot seem to improve it. Any suggestions for alternative ideas?
I want to create a big figure using matplotlib, and then save a few parts of it at different specific coordinates (so manual zooming after plt.show() is not an option - there is no guarantee I can zoom to some precise coordinates - or is there?). The picture is fairly large, so I don't want to generate it all over again and again, specifying xlim and ylim every time before plotting. Is there any way to change axes limits after the figure is created? And I am not using an ipython console, but I need to use it in a script.
There is no problem with using xlim and ylim here. Take the following example:
import matplotlib.pyplot as plt
plt.plot(range(20))
plt.savefig("1.png")
plt.xlim(0,10)
plt.savefig("2.png")
plt.xlim(0,30)
plt.savefig("3.png")
Here a diagonal line is plotted, then we zoom into the first half of the line, then we zoom back out. At each stage a new png file is created. There is no need for redrawing here.
I've plotted a bunch of scatter points then redraw the canvas:
self.display_points = ax.scatter(x,y)
wx.CallAfter(self.display.canvas.draw)
I have an object which contains the color. If this is changed by the user from the GUI, I want to be able to change the color of the points without having to replot the data.
def _color_changed(self):
if hasattr(self, '_display_points'):
self._display_points.set_facecolors(self.color)
wx.CallAfter(self.display.canvas.draw)
how is this done for the size of the marker and the type of marker... ie. what should X be in _display_points.set_X to change each of the plotted components. Is there somewhere these attributes can be found? Thanks.
scatter returns a PathCollection object, which you can see has a relatively limited api for setting things after the fact. The Collection family of classes trades the ability to update later for more efficient drawing.
If you are not using scatter's ability to set the size and color of each point separately you are much better off using
self.display_points, = ax.plot(x, y, marker='o', linestyle='none')
which will give you a Line2D object back and look identical your scatter plot. Line2D has a much more flexible api which includes set_marker and set_markersize.
I am trying to minimize margins around a 1X2 figure, a figure which are two stacked subplots. I searched a lot and came up with commands like:
self.figure.subplots_adjust(left=0.01, bottom=0.01, top=0.99, right=0.99)
Which leaves a large gap on top and between the subplots. Playing with these parameters, much less understanding them was tough (things like ValueError: bottom cannot be >= top)
My questions :
What is the command to completely minimize the margins?
What do these numbers mean, and what coordinate system does this follow (the non-standard percent thing and origin point of this coordinate system)? What are the special rules on top of this coordinate system?
Where is the exact point this command needs to be called? From experiment, I figured out it works after you create subplots. What if you need to call it repeatedly after you resize a window and need to resize the figure to fit inside?
What are the other methods of adjusting layouts, especially for a single subplot?
They're in figure coordinates: http://matplotlib.sourceforge.net/users/transforms_tutorial.html
To remove gaps between subplots, use the wspace and hspace keywords to subplots_adjust.
If you want to have things adjusted automatically, have a look at tight_layout
Gridspec: http://matplotlib.sourceforge.net/users/gridspec.html
I have a matplotlib axes instance inside which I'm animating an AxesImage via blitting.
What I'd like to do is animate the ticks on the x-axis as well.
I am updating the data on the AxesImage (and subsequently) drawing its artist quite frequently, and on each update I'd like to move one extra tick placed to highlight the position of something.
This is what I'm doing right now:
axis = axes.get_xaxis
im.set_data(new_data)
axis.set_ticks([10,20,30,x,t])
axis.set_ticklabels(["p", "u", "z", "z", "i"])
axes.draw_artist(im)
axes.draw_artist(axis)
While I see the ticks correctly updating, the labels are not. I think that the axes bbox does not include the axes, is this possible? If so, how can I animate it? Should I copy and restore from somewhere else?
The axes bbox doesn't include anything outside of the "inside" of the axes (e.g. it doesn't include the tick labels, title, etc.)
One quick way around this is to just grab the entire region of the figure when you're blitting. (E.g. background = canvas.copy_from_bbox(fig.bbox))
This can cause problems if you have multiple subplots and only want to animate one of them. In that case, you can do something along the lines of background = canvas.copy_from_bbox(ax.bbox.expanded(1.1, 1.2)). You'll have to guesstimate the ratios you need, though.
If you need the exact extent of the tick labels, it's a bit trickier. The easiest way is to iterate through the ticklabel objects and get the union with ax.bbox. You can make this a one-liner: ax.bbox.union([label.get_window_extent() for label in ax.get_xticklabels()]).
At any rate, one of those three options should do what you need, I think.