Do I need a figure? What are they for? - python

I have begun using matplotlib and I am somewhat confused as to why figures exist. Sometimes I see code where a figure is declared and then a plot is made, and sometimes I see things like this:
import numpy as np
import matplotlib.pyplot as plt
data = np.loadtxt('initial.dat','float')
plt.plot(data[:,0], data[:,1])
plt.xlabel("x (Angstroms)")
plt.ylabel("V (eV)")
plt.savefig('v.png',bbox_inches='tight')
plt.clf()
I read the documentation on figure and plot, but I don't get it. Why do figures exist?

A figure will always exist once you create some plot with matplotlib.
The introductory matplotlib page may help here:
The whole figure. The figure keeps track of all the child Axes, a smattering of ‘special’ artists (titles, figure legends, etc), and the canvas. (Don’t worry too much about the canvas, it is crucial as it is the object that actually does the drawing to get you your plot, but as the user it is more-or-less invisible to you). A figure can have any number of Axes, but to be useful should have at least one.
You can imagine the figure to be the white sheet of paper you draw a plot on. A figure has some size, maybe a background and most importantly it is the container for everything you draw into it. In most cases this will be one or more axes. If there wasn't any figure, there wouldn't be any sheet of paper to draw your plot to (you cannot draw a line in the air).
Even if you haven't explicitely created the figure, it is automatically created in the background.
import matplotlib.pyplot as plt
plt.plot([1,2,3])
# at this point we already have a figure, because the plot needs to live somewhere
# we can get a handle to the figure via
figure = plt.gcf()
Examples of when you explicitely need a figure:
If you want to create a second figure.
plt.plot([1,2,3])
plt.figure(2)
plt.plot([2,4,6])
If you want to set the figure size or other figure parameters.
plt.figure(figsize=(5,4), dpi=72)
If you want to change the padding of the subplot(s).
fig, ax=plt.subplots()
fig.subplots_adjust(bottom=0.2)

Related

How to make plots customizable in python

I have two issues with my python plot that would be grateful if anyone could help me with:
1- I wonder if it is possible in python to have the option for the plots after display to add horizontal or vertical lines, so that these new lines could be added, moved or deleted without the need to run the code again.
to say it more clearly, I am looking for additional features that adding them does not need to change the code and they only enable me to manually draw on the already plotted image.
2- I want to plot a very large image in the real size, So that I need to add the horizontal and vertical slide bars to be able to scroll up/down or left/right in the plot?
I need to combine these two ability for my project, can someone help me with that?
1- You can't physically draw on it, but you can make a plot in matplotlib interactive as follows:
import matplotlib.pyplot as plt
plt.ion() # turns on interactive mode
fig = plt.figure()
ax = fig.add_subplot()
plt.ylim(-10, 10)
plt.xlim(0, 10)
while True:
plt.axhline(float(input("number")))
fig.canvas.draw()
fig.canvas.flush_events() # draws
This program allows you to create horizontal lines based on user input.
I think you can solve 2 with tkinter, but that would be pretty difficult. There might also an easier way. See this stack overflow question for an example of an interactive plot in tkinter. I believe this plot can be made bigger and scrollable, but I am not sure.

Is there a way to change the ticks for ALL the future plots with matplotlibs

I have an unusual request, but I have a question that has been bothering me for some time regarding matplotlib.
When I plot figures, even with the basic commands, for example (example), my plots do not have the same look. That is to say that in my case the ticks are systematically on the outside and only on the left and bottom edges, see:
My plot with outside ticks + only 2 axis with ticks on.
However, while looking at some ppl plots, they don't look like this, and they systematically have the four sides with ticks that are pointing inside the plot:
Plot from someone giving tips on stackoverflow
I know how to modify this for a single particular plot. But I would like to know if there is a way to specify somewhere that all my plots should have this style.
Is it possible to do so?
You can patch the Figure.add_subplot method and put your customization in there. For example:
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
_original_add_subplot = Figure.add_subplot
def new_add_subplot(*args, **kwargs):
ax = _original_add_subplot(*args, **kwargs)
ax.tick_params(left='on', right='on', top='on', bottom='on')
return ax
Figure.add_subplot = new_add_subplot
fig, ax = plt.subplots()
ax.axline((0,0), slope=1)
plt.show()
Then you could put all this in a separate package which would execute this when imported. So all you would need to do is import mplcustom. If that's still too much work, you can also put the code into sitecustomize or usercustomize modules, which will be imported automatically on startup (see Site-specific configuration hook for more information).

Clearing the Matplotlib plot without clearing slider

I'm currently creating an application where I need to update matplotlib graphs. I'm stuck at following step.
I have a scatter plot and slider in the same figure. Upon changing the slider value, I need to clear the scatter plot without clearing the slider. Following is the code I implemented, but it does not clear the plot.
The .clf() function removes both the slider and scatter plot. Is there a way I could remove only the plot without impacting the slider?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
X1=np.arange(10)
Y1=np.arange(10)
Z1=np.arange(10)
fig,ax=plt.subplots()
ax=plt.scatter(X1,Y1,Z1)
axSlider1=plt.axes([0.3,0.9,0.3,0.05])
Slder2=Slider(ax=axSlider1,label='Slider',valmin=1,valmax=4,valinit=2)
plt.show()
# Function to clear the scatter plot without effecting slider.
def val_update(val):
plt.cla()
Slder2.on_changed(val_update)
fig,ax=plt.subplots()
Assigned the Axes object to ax - then
ax=plt.scatter(X1,Y1,Z1)
assigns a PathCollection object to ax. So val_update is tying to act on the wrong thing.
This seems to solve the issue you asked about.
X1=np.arange(10)
Y1=np.arange(10)
Z1=np.arange(10)
fig,ax=plt.subplots()
path=plt.scatter(X1,Y1,Z1)
axSlider1=plt.axes([0.3,0.9,0.3,0.05])
Slder2=Slider(ax=axSlider1,label='Slider',valmin=1,valmax=4,valinit=2)
# Function to clear the scatter plot without effecting slider.
def val_update(val):
print(val)
ax.clear()
Slder2.on_changed(val_update)
plt.show()
The Matplotlib Gallery is a good resource you can browse through it looking for features you want and see how they were made. - Like this slider demo
If you think you will be using matplotlib in the future I would recommend working your way through the Introductory tutorials and at least the Artists tutorial

Save colorbar for scatter plot separately

I've got scatter plot with colorbar which I save as PNG image. I need the plot to be of a certain figsize but adding colorbar scales original plot.
import pylab as plt
plt.figure(figsize=FIGSIZE)
plt.scatter(X, Y, c=Z, s=marker_size, norm=LogNorm(), vmin=VMIN, vmax=VMAX, cmap=CMAP,rasterized=True,lw=0,)
CB = plt.colorbar(ticks=TICKS, format=FORMAT)
How could I save original plot (with figsize set as above) and colorbar as two separate images?
The obvious answer is "plot your colorbar separately". You need to create a new figure window and plot your colorbar there, in order to prevent your first figure from being distorted. Small example:
import matplotlib.pyplot as plt
import numpy as np # only for dummy data
X,Y = np.mgrid[-2:3,-2:3]
Z = np.random.rand(*X.shape)
FIGSIZE = (2,3)
plt.figure(figsize=FIGSIZE)
mpb = plt.pcolormesh(X,Y,Z,cmap='viridis')
# plot the original without a colorbar
plt.savefig('plot_nocbar.png')
# plot a colorbar into the original to see distortion
plt.colorbar()
plt.savefig('plot_withcbar.png')
# draw a new figure and replot the colorbar there
fig,ax = plt.subplots(figsize=FIGSIZE)
plt.colorbar(mpb,ax=ax)
ax.remove()
plt.savefig('plot_onlycbar.png')
# save the same figure with some approximate autocropping
plt.savefig('plot_onlycbar_tight.png',bbox_inches='tight')
Consider the following four figures that were produced (click to view properly):
The first is a saved version of the figure without a call to colormap. This is fine, this is what you want to preserve. The second figure shows what happens if we call colorbar without any extra fuss: it takes some space from the original figure, and this is what you want to prevent.
You have to open a new figure (and axes) using plt.subplots, with the size of your original figure. This way you can be sure that the produced colorbar will be the same size as if it was drawn in your original figure. In the above setup I let matplotlib determine the size of the colorbar itself; but then afterward we need to delete the auxiliary axes that would pollute the resulting plot. (The other option would be to create a single axes in the new figure manually, with the expected size of the colorbar. I suspect this is not a feasible course of action.)
Now, as you can see in the third plot, the empty space left after the deleted axes is clearly visible in the resulting plot (but the size of the colorbar is perfect, correspondingly). You can either cut this white space off manually in post-production, or use something that autocrops your colorbar image.
I also included a version of the plot wherein matplotlib itself crops most of the figure: the bbox_inches='tight' keyword argument to savefig does exactly this. The upside is that the resulting image file only contains the colorbar (as seen above in the fourth image), but the size of the resulting colorbar will be slightly different from your original. Depending on your specific needs, you'll need to experiment with the available methods to come up with a solution that's most convenient for you.

Save images of a matplotlib figure at different coordinates?

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.

Categories