Adding multiple Pull Plots with matplot lib - python

I was working in a plot that had a pull plot, which I defined as :
fig, (ax1, ax2) = aplt.ratio_plot(name= canvasArray[kl], figsize=(800, 800), hspace=0.05)
and it was working fine, but now I have the need to add another pull plot in the image, so i tried:
fig, (ax1, ax2,ax3) = aplt.subplots(3,1,name="fig1", figsize=(850, 950))
and i got the resulting plot:
I tried some options like .set_aspect() but i keep getting the error AttributeError: 'Axes' object has no attribute 'set_aspect'. I would like that the main plot ocupy 2/4 of the full plot, and the pull plots 1/2 each, but i am having dificulties with that.
I am working in a object oriented enviroment, so i dont know if that changes things. I am using the Atlasplots package which uses matplotlib syntax. https://atlas-plots.readthedocs.io/en/latest/

I had an idea. Matplotlib.pyplot has a collection of parameters, and one of them controls the size of the plots. It is called: rcParams. This attribute internally is a dictionary that contains a lot of configurations. Take a look:
>>> from matplotlib import pyplot as plt
>>> plt.rcParams
If you run the above lines of code you get the following. Yeah, those are a lot of things, but we have one specific key that may solve our problem. It is "figure.figsize", if you select this parameter like this:
>>> plt.rcParams["figure.figsize"] = [6.0, 4.0]
You can customize the plot sizes. So I think you would be able to use this at certain locations in your code and reset it to the default values when needed.
To see what are the default values, just run this to get the output based on the key "figure.figsize":
>>> plt.rcParams["figure.figsize"]
[out]: ["your default", "values here"]
Update: October 1, 2021
I've just remembered that you can also unpack subplots (matplotlib.pyplot.subplots) and select directly the parameters, like this:
>>> fig, ax = plt.subplots(figsize=("the size", "you want"))
I've also noticed something very interesting. If you use rcParams["figure.figsize"] to control plot size, it will be persistent throughout the code, but if you use the option shown in the update, the configuration will apply only to that plot area. That is a behavior that I've observed here.

Related

Why isn't plt.figure(figsize=(X,y)) changing the size on my .hist and .plot?

I'm getting a bit confused around the concepts of axes, and frankly - what modifies what when it comes to the matplotlib backend. I was told in this post that "whenever you first do something that requires an axes object, one is created for you and becomes the default object that all of your future actions will be applied to until you change the current axes to something else."
But why is it, then, that figsize doesn't seem to do anything when I use the following code in the same cells in a Jupyter notebook:
dataset[['TV','radio']].plot()
plt.figure(figsize=(5,10))
and also
dataset.hist()
plt.figure(figsize=(10,20))
Why don't either of these work? How can I tell which axes object I'm referencing? Thanks so much
The problem is that plt.figure creates a new figure.
If you want to resize the existing figure use this:
dataset[['TV','radio']].plot()
fig = plt.gcf() # gcf: get current figure
fig.set_size_inches(5,10)
Another way you could do it -- that's illustrative of how axes get created and later used -- is to start off with the figure size like this:
import numpy as np, pandas as pd
df = pd.DataFrame({'x':[np.random.randint(0,10) for i in range(10)]})
fig = plt.figure(figsize=(5,5))
ax = fig.gca() # gca: get current axes
df.plot(ax=ax)
Result:

how to make easy and efficient plots on Python

I use matplotlib for my plots, I find it great, but sometimes too much complicated. Here an example:
import matplotlib.pyplot as plt
import numpy as np
idx1 = -3
idx2 = 3
x = np.arange(-3, 3, 0.01)
y = np.sin(np.pi*x*7)/(np.pi*x*7)
major_ticks = np.arange(idx1, idx2, 1)
minor_ticks = np.arange(idx1, idx2, 0.1)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_ylim(-0.3, 1.2)
ax.set_xlim(idx1, idx2)
ax.set_xticks(major_ticks)
ax.set_xticks(minor_ticks, minor = True)
ax.grid(True, which = 'both')
ax.tick_params(axis = 'x', labelsize = 18)
ax.tick_params(axis = 'y', labelsize = 18)
ax.plot(x, y)
plt.show()
Is there anything implemented on matplotlib and/or seaborn in which I can provide all these plot settings just as argument of a function only? It may considerably reduce the number of code lines and make the script easier both to write and understand.
Matplotlib provides an object oriented API. This means that all the elements of the figure are acutally objects for which one can get and set properties and which can be easily manipulated. This makes matplotlib really flexible such that it can produce almost any plot you'd imagine.
Since a plot may consist of a hundred or more elements, a function that would allow the same flexibility would need that amount of possible arguments. It is not necessarily easier to remember all possible arguments of a function than all possible attributes of a class.
Having a single function call that does all of this, does not necessarily mean that you have to type in less characters. The commands would just be ordered differently.
Furthermore the object oriented approach allows to keep things seperate. Some properties of the axes, like the grid or the axis labels are completely independend on what you plot to the axes. So you wouldn't want to set the xticks in the call to plot, because they are simply not related and it may be very confusing to set twice the same ticklabels when plotting two lines in the same axes.
On the other hand, matplotlib is really easy. In order to produce a plot you need two lines
import matplotlib.pyplot as plt
plt.plot([1,2,3],[2,1,3])
which sets most of the parameters exactly as they are needed. The more you want to customize this plot, the more settings you have to apply. Which is fine as it allows the user himself to determine how much in depth he wants to control the appearance of the plot.
Most matplotlib codes can be separated into three parts.
Setting the style
Creating the plot
Customizing the plot
Setting the style in the case of the code from the question involves e.g. the ticklabel size and the use of a grid. Those properties can set as it's done in the code but it may indeed be that one always wants to use the same properities here and finds it annoying to type the same parameters in every time one creates a plot. Therefore matplotlib provides general style settings, called rcParams. They can be set at the beginning of a script, e.g.
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['axes.grid '] = True
plt.rcParams['axes.labelsize'] = 18
and will be applied to all plots within the script. It is also possible to define a complete stylesheet using those parameters. For more information see the Customizing matplotlib article.
It is equally possible to use predefined stylesheets for certain applications.
Simply importing import seaborn is also a possible way to change the style.
Creating the plot can not be simplified much more. It's clear that one needs as many plotting commands as items to plot. Creating the figure and axes like
fig, ax = plt.subplots()
saves one line though.
Equally no simplification is possible if customizing ticks or tickmarks are required. One may however consider to use Tickers and Formatters for this purpose.
At the end one may of course consider to write a custom function which performs much of those tasks, but everyone can decide if that is useful for himself.
Browsing around I saw this wabe page.
This line of code can summarise many settings
import matplotlib as mpl
mpl.rc('lines', linewidth=2, color='r')
ax.set is very useful for this:
ax.set(xlim=(idx1, idx2), ylim=(-0.3, 1.2),
xticks=major_ticks, ...)
You can only set simple single-argument properties (e.g. those which don't need further keywords), but it's a nice timesaver.

Can I save to disk a plot generated by pandas df.plot? [duplicate]

In ipython Notebook, first create a pandas Series object, then by calling the instance method .hist(), the browser displays the figure.
I am wondering how to save this figure to a file (I mean not by right click and save as, but the commands needed in the script).
Use the Figure.savefig() method, like so:
ax = s.hist() # s is an instance of Series
fig = ax.get_figure()
fig.savefig('/path/to/figure.pdf')
It doesn't have to end in pdf, there are many options. Check out the documentation.
Alternatively, you can use the pyplot interface and just call the savefig as a function to save the most recently created figure:
import matplotlib.pyplot as plt
s.hist()
plt.savefig('path/to/figure.pdf') # saves the current figure
Plots from multiple columns
Added from a comment toto_tico made on 2018-05-11
If you are getting this error AttributeError: 'numpy.ndarray' object has no attribute 'get_figure', then it is likely that you are plotting multiple columns.
In this case, ax will be an array of all the axes.
ax = s.hist(columns=['colA', 'colB'])
# try one of the following
fig = ax[0].get_figure()
fig = ax[0][0].get_figure()
fig.savefig('figure.pdf')
You can use ax.figure.savefig():
import pandas as pd
s = pd.Series([0, 1])
ax = s.plot.hist()
ax.figure.savefig('demo-file.pdf')
This has no practical benefit over ax.get_figure().savefig() as suggested in Philip Cloud's answer, so you can pick the option you find the most aesthetically pleasing. In fact, get_figure() simply returns self.figure:
# Source from snippet linked above
def get_figure(self):
"""Return the `.Figure` instance the artist belongs to."""
return self.figure
You can simply save your (e.g. histogram) plot like this:
df.plot.hist().get_figure().savefig('name')
Just wanted to add that the default resolution is 100dpi, which is fine for screen but won't work if you want to enlarge or print it. You can pass a 'dpi' parameter to get a high-resolution file:
ax = s.hist() # s is an instance of Series
ax.figure.savefig('/path/to/figure.png', dpi=300)

How to separate one graph from the set of multiple graphs on figure

I will not be able to put the code here because it is my assignment.
My program is printing multiple graphs on one plot. Please look at the example figure on the following link: Python: Plot multiple graphs on the same figure
The link above is just an example. That is not my code nor do I have the same program. My topic is completely different. That figure is just for reference.
The line of code I am using to achieve this is: plot(a,b, label=str(meters))
What I want to do is get any one of those graph from those three curves and also plot it separately as if it is the main graph. I am doing all this inside a function, and I have created an array of numbers to loop through these different values to get three different graphs.
Do you mean something like this?
import numpy as np
import matplotlib.pyplot as plt
plt.ion()
a = np.arange(5)
line1, = plt.plot(a, a**2) # a new figure instance is opened automatically
line2, = plt.plot(a, a**3-a)
line3, = plt.plot(a, 4*a-a**2/2.)
fig_handle = plt.figure() # Force a new figure instance to open
plt.plot(a, a**2) # This will replot 'line1', but in this new figure instance.
If not, please update your question, perhaps showing the code you already have.
Note that this is information you could find on the matplotlib pyplot tutorial.

Setting Yaxis in Matplotlib using Pandas

Using Pandas to plot in I-Python Notebook, I have several plots and because Matplotlib decides the Y axis it is setting them differently and we need to compare that data using the same range.
I have tried several variants on: (I assume I'll need to apply the limits to each plot.. but since I can't get one working... From the Matplotlib doc it seems that I need to set ylim, but can't figure the syntax to do so.
df2250.plot(); plt.ylim((100000,500000)) <<<< if I insert the ; I get int not callable and if I leave it out I get invalid syntax. anyhow, neither is right...
df2260.plot()
df5.plot()
I'm guessing this was a feature added after this answer was accepted in 2013; DataFrame.plot() now exposes a ylim parameter that sets the y axis limits:
df.plot(ylim=(0,200))
See pandas documentation for details.
Pandas plot() returns the axes, you can use it to set the ylim on it.
ax1 = df2250.plot()
ax2 = df2260.plot()
ax3 = df5.plot()
ax1.set_ylim(100000,500000)
ax2.set_ylim(100000,500000)
etc...
You can also pass an axes to Pandas plot, so plotting it in the same axes can be done like:
ax1 = df2250.plot()
df2260.plot(ax=ax1)
etc...
If you want a lot of different plots, defining the axes beforehand and within one figure might be the solution that gives you the most control:
fig, axs = plt.subplots(1,3,figsize=(10,4), subplot_kw={'ylim': (100000,500000)})
df2260.plot(ax=axs[0])
df2260.plot(ax=axs[1])
etc...

Categories

Resources