Is there a method in matplotlib to set the attributes of a plot BEFORE actually plotting it?
To the context: I have a config file in which I configure aspects of a plot. However, some keys may not be needed to be set (as e.g. the linewidth). I would like to have a function which says something like this :
if 'linethicknes' in config:
ax.set_linewidth = linethickness
I know that there is the possibility to give the linewidth property in the ax.plot(x, y ,linewidth = 1). But here the attribute is set in the plotting function, and I need to set it before the plotting.
Is it possibile to set the linewidth (and other attributes) before this plotting function?
You can set the runtime configuration rcparams at the start and this will set the configuration. As long as you don't overwrite it, this will be set as the configuration. A simple example is given below...
plt.rcParams['lines.linewidth'] = 6.0
x=[1,2,3,4,5]
y=[5,4,3,2,1]
plt.plot(x, y)
plt.show()
Related
Even though I set the plotting style in every plotting script manually right at the beginning of the code, directly after importing the modules, the figure-plotting-style to seaborn-whitegrid, the resulting figures comprise the plain matplotlib.pyplot standard white background without grid display, e.g. like this graph:
Therefore, I assume that setting the style has no effect on my scripts, but I can't tell where it goes wrong, or where the style changes back to default. It'd be practical to print out the currently active plotting style at any given point, e.g. during a debugging session.
This is how I set my plotting style:
import .....
import matplotlib.pyplot as plt
import .....
# * Set the matplotlib.pyplot default template (plotting style and background) *
plt.style.use('seaborn-whitegrid')
# Start of script #
...
I even inserted the line plt.style.use('seaborn-whitegrid') in my plotting-submodules, which the main script calls, but it doesn't seem to have an effect on the output.
EDIT on additional trials:
According to what was suggested below by #Bernardo Trindade, I replaced plt.style.use with mpl.style.use:
# * Set the matplotlib.pyplot default template (plotting style and background) *
mpl_plt_default_template = 'seaborn-whitegrid'
import matplotlib as mpl
mpl.style.use(mpl_plt_default_template)
What I also tried is temporary styling, but with no avail either:
# Set plotting style
with plt.style.context('seaborn-whitegrid'):
# * Instantiate figure
fig, axs = plt.subplots(rows, cols, figsize=(width, height))
....
All of the above has not lead to any difference in the output graphs; still showing the plain standard matplotlib background without grid etc.
System specifics:
Lubuntu 20.04 LTS,
python 3.9x,
VS Code
I don't think there's a variable that stores the name of the stylesheet currently used, as all the style information is kept in a large dictionary whose values are simply updated when calling matplotlib.style.use().
Have you tried:
import matplotlib as mpl
mpl.style.use('seaborn-whitegrid')
Finally I found the culprit:
ax.grid(which='both', alpha=1)
Previously, this line never caused an issue, the grids were displayed just fine.
By contrast, now this setting the grid like this renders the grid invisible.
1) CONCLUSION (short answer)
The easiest way to make it work, i.e. safeguard that the grid appears, is setting either the parameter b to True like so:
ax.grid(b=True, which='both', alpha=1)
Alternatively, the kwarg visible can be set to True like so:
ax.grid(which='both', alpha=1, visible=True)
I recommend using visible=True since the naming of the kwarg is more intuitive as to what it actually does, compared to the optional parameter merely called b.
2) ELABORATE ANSWER
The following information is based on the official matplotlib docs:
The allegedly optional parameter b must be set manually to True or False, because otherwise, it'll be set to None in this context,
even though the current docs state:
b : bool or None, optional
Whether to show the grid lines. If any kwargs are supplied, it is assumed you want the grid on and b will be set to True.
If b is None and there are no kwargs, this toggles the visibility of the lines.
NOTE on boolean parameter "b":
I've tried both True and False to find out that even False delivers a proper grid, which is counterintuitive.
On the contrary, when put explicitely to None, which is equivalent to passing nothing, the grid won't appear:
ax.grid(b=None, which='both', alpha=1)
As mentioned before, the grid is invisible in this context also with the following, which was my original code line:
ax.grid(which='both', alpha=1)
Skimming through the **kwargs revealed an extra visibility kwarg called visible:
NOTE on naming of the visibility kwarg in its docs:
Artist.set_visible(self, b)[source]
It is called b, just like the
optional parameter
of ax.grid().
I confirmed that they actually do the same thing.
The grid appears, when putting the visible-kwarg to True:
ax.grid(b=None, which='both', alpha=1, visible=True)
When put to contradictory values, the following error is thrown:
ValueError: 'b' and 'visible' specify inconsistent grid visibilities
This error is caused when employing one of the following two possibilities:
ax.grid(b=False, which='both', alpha=1, visible=True)
ax.grid(b=True, which='both', alpha=1, visible=False)
Eventually, to make the grid appear successfully, set either the parameter b to True like so:
ax.grid(b=True, which='both', alpha=1)
Alternatively, the kwarg visible can be set to True like so:
ax.grid(which='both', alpha=1, visible=True)
I do a fair amount of plotting with pandas and matplotlib, and I've been looking for a way to help set the default scatter styles in my matplotlibrc file. I do not want to have to edit the matplotlib sourcecode to get default behaviors, because I need to be able to allow coworkers to reproduce work (and want to keep things consistent between machines/VEs, and update without worrying about busting things).
As an example, I want to be able to do:
plt.scatter(
df["dep_var"],
df["ind_var"],
alpha=0.5,
facecolors="none",
edgecolors="#444444",
linewidth=2,
)
With:
plt.scatter(
df["dep_var"],
df["ind_var"],
)
With overwritten alpha, face colors, edge colors, and linewidth in the matplotlibrc file (or some other non-source code location). But when I add
scatter.alpha : 0.5
to my matplotlibrc file, I get a Bad Key warning.
Is there a way to achieve this?
I think that a possible solution is use the RC parameter like:
plt.rcParams["scatter.edgecolors"] = "#444444"
plt.rcParams["lines.linewidth"]=2
You can check more about ket for Rc here
You only need to run this once! If you restart the kernel it will be reverted to the default.
I've done a fair amount of research on adding a colorbar to a plot but I'm still really confused about how to add one. The examples I've seen use different ways of doing so, which just confuses me because I don't get what the "right" way is.
I've seen there is a colorbar method and a colorbar() function, so what should one use to simply add a colorbar?
Some examples do this:
fig,ax = plt.subplots()
s = ax.scatter(x,y,cmap = coolwarm)
matplotlib.colorbar.ColorbarBase(ax=ax, cmap=coolwarm, values=sorted(v),
orientation="horizontal")
While some others simply call the function:
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
image = np.random.poisson(10., (100, 80))
i = ax.imshow(image, interpolation='nearest')
fig.colorbar(i)
I'm probably missing something here, but I just don't see how these both create a colorbar (I just copied the code for the colorbar and excluded that of the data).
My question is simply: what is the simplest way to add a colorbar to a plot?
Thanks!
The first example you quote creates an instance of ColorbarBase. This is usually not the recommended way; there might be some exceptions, but in general there is absolutely no reason to use this.
The second example you quote is one or even the way to create a colorbar inside a figure. Using this, you are on the save side. Using the colorbar method of the figure instance makes it clear in which figure to place the colorbar and supplying the respective ScalarMappable (in this case an AxesImage) ensures that the colorbar uses the correct colors from that ScalarMappable.
fig, ax = plt.subplots()
im = ax.imshow(image)
fig.colorbar(im)
or
fig, ax = plt.subplots()
sc = ax.scatter(x,y, c=something)
fig.colorbar(sc)
There is an even easier method, which would be to simply call
plt.colorbar()
Note however that this may lead to confusions as it tries to automatically determine the plot for which the colorbar should be created. Thus, there is some chance that it fails and I would not recommend using it.
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.
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...