How to set the alpha value for matplotlib plots globally - python

Using Jupyther Notebooks i often find myself repeadily writing the following to change the alpha value of the plots:
plot(x,y1, alpha=.6)
plot(x,y2, alpha=.6)
...
I was hoping to find a matching value in the rcParameters to change to option globally like:
plt.rcParams['lines.alpha'] = 0.6 #not working
What is a possible workaround to change the alpha value for all plots?

Unfortunately, based on their How to entry:
If you need all the figure elements to be transparent, there is currently no global alpha setting, but you can set the alpha channel on individual elements.
So, via matplotlib there's currently no way to do this.
What I usually do for global values is define an external configuration file, define values and import them to the appropriate scripts.
my_conf.py
# Parameters:
# matplotlib alpha
ALPHA = .6
my_plots.py
import conf.py as CONF
plot(x,y1, alpha=CONF.ALPHA)
plot(x,y2, alpha=CONF.ALPHA)
This usually helps in keeping configuration separated and easy to update.

Answering my own question with help of the matplotlib team the following code will do the job by changeing the alpha value of the line colors globally:
alpha = 0.6
to_rgba = matplotlib.colors.ColorConverter().to_rgba
for i, col in enumerate(plt.rcParams['axes.color_cycle']):
plt.rcParams['axes.color_cycle'][i] = to_rgba(col, alpha)
Note: In matplotlib 1.5 color_cycle will be deprecated and replaced by prop_cycle
The ability the set the alpha value over the rcParams has also been added to the wishlist for Version 2.1

Updated version (perhaps cleaner available) :
from cycler import cycler
alpha = 0.5
to_rgba = matplotlib.colors.ColorConverter().to_rgba#
color_list=[]
for i, col in enumerate(plt.rcParams['axes.prop_cycle']):
color_list.append(to_rgba(col['color'], alpha))
plt.rcParams['axes.prop_cycle'] = cycler(color=color_list)

Another way to do it is just to specify the alpha and pass this to the rcParams
plt.rcParams['axes.prop_cycle'] = cycler(alpha=[0.5])
Bear in mind that this can be combined with any other cycling properties such as the color and line style.
cyc_color = cycler(color=['r','b','g')
cyc_lines = cycler(linestyle=['-', '--', ':'])
cyc_alpha = cycler(alpha=[0.5, 0.3])
cyc = (cyc_alpha * cyc_lines * cyc_color)
Be careful with the order of your cyclers, as the sequence above will cycle through colors, then lines, then alphas.

Related

How can i Plot arrows in a existing mplsoccer pitch?

I tried to do the tutorial of McKay Johns on YT (reference to the Jupyter Notebook to see the data (https://github.com/mckayjohns/passmap/blob/main/Pass%20map%20tutorial.ipynb).
I understood everything but I wanted to do a little change. I wanted to change plt.plot(...) with:
plt.arrow(df['x'][x],df['y'][x], df['endX'][x] - df['x'][x], df['endY'][x]-df['y'][x],
shape='full', color='green')
But the problem is, I still can't see the arrows. I tried multiple changes but I've failed. So I'd like to ask you in the group.
Below you can see the code.
## Read in the data
df = pd.read_csv('...\Codes\Plotting_Passes\messibetis.csv')
#convert the data to match the mplsoccer statsbomb pitch
#to see how to create the pitch, watch the video here: https://www.youtube.com/watch?v=55k1mCRyd2k
df['x'] = df['x']*1.2
df['y'] = df['y']*.8
df['endX'] = df['endX']*1.2
df['endY'] = df['endY']*.8
# Set Base
fig ,ax = plt.subplots(figsize=(13.5,8))
# Change background color of base
fig.set_facecolor('#22312b')
# Change color of base inside
ax.patch.set_facecolor('#22312b')
#this is how we create the pitch
pitch = Pitch(pitch_type='statsbomb',
pitch_color='#22312b', line_color='#c7d5cc')
# Set the axes to our Base
pitch.draw(ax=ax)
# X-Achsen => 0 to 120
# Y-Achsen => 80 to 0
# Lösung: Y-Achse invertieren:
plt.gca().invert_yaxis()
#use a for loop to plot each pass
for x in range(len(df['x'])):
if df['outcome'][x] == 'Successful':
#plt.plot((df['x'][x],df['endX'][x]),(df['y'][x],df['endY'][x]),color='green')
plt.scatter(df['x'][x],df['y'][x],color='green')
**plt.arrow(df['x'][x],df['y'][x], df['endX'][x] - df['x'][x], df['endY'][x]-df['y'][x],
shape='full', color='green')** # Here is the problem!
if df['outcome'][x] == 'Unsuccessful':
plt.plot((df['x'][x],df['endX'][x]),(df['y'][x],df['endY'][x]),color='red')
plt.scatter(df['x'][x],df['y'][x],color='red')
plt.title('Messi Pass Map vs Real Betis',color='white',size=20)
It always shows:
The problem is that plt.arrow has default values for head_width and head_length, which are too small for your figure. I.e. it is drawing arrows, the arrow heads are just way too tiny to see them (even if you zoom out). E.g. try something as follows:
import pandas as pd
import matplotlib.pyplot as plt
from mplsoccer.pitch import Pitch
df = pd.read_csv('https://raw.githubusercontent.com/mckayjohns/passmap/main/messibetis.csv')
...
# create a dict for the colors to avoid repetitive code
colors = {'Successful':'green', 'Unsuccessful':'red'}
for x in range(len(df['x'])):
plt.scatter(df['x'][x],df['y'][x],color=colors[df.outcome[x]], marker=".")
plt.arrow(df['x'][x],df['y'][x], df['endX'][x] - df['x'][x],
df['endY'][x]-df['y'][x], color=colors[df.outcome[x]],
head_width=1, head_length=1, length_includes_head=True)
# setting `length_includes_head` to `True` ensures that the arrow head is
# *part* of the line, not added on top
plt.title('Messi Pass Map vs Real Betis',color='white',size=20)
Result:
Note that you can also use plt.annotate for this, passing specific props to the parameter arrowprops. E.g.:
import pandas as pd
import matplotlib.pyplot as plt
from mplsoccer.pitch import Pitch
df = pd.read_csv('https://raw.githubusercontent.com/mckayjohns/passmap/main/messibetis.csv')
...
# create a dict for the colors to avoid repetitive code
colors = {'Successful':'green', 'Unsuccessful':'red'}
for x in range(len(df['x'])):
plt.scatter(df['x'][x],df['y'][x],color=colors[df.outcome[x]], marker=".")
props= {'arrowstyle': '-|>,head_width=0.25,head_length=0.5',
'color': colors[df.outcome[x]]}
plt.annotate("", xy=(df['endX'][x],df['endY'][x]),
xytext=(df['x'][x],df['y'][x]), arrowprops=props)
plt.title('Messi Pass Map vs Real Betis',color='white',size=20)
Result (a bit sharper, if you ask me, but maybe some tweaking with params in plt.arrow can also achieve that):

plotnine geom_boxplot ignores required aesthetic and requires unnecessary aesthetic

I have data that looks like:
Scenario ymin lower middle upper ymax
One 16362.586379 20911.338893 27121.693254 35219.449009 46406.087619
Two 19779.003240 25390.096116 33108.174561 43545.202225 58464.277060
Rather than use all 50 k data points for every Scenario (there are many more than One and Two), I've computed the positions I need for the box and whiskers.
I try to plot this via
import pandas
import plotnine as p9
df = pandas.read_excel('boxplot_data.xlsx', sheet='Sheet1')
gg = p9.ggplot()
gg += p9.geoms.geom_boxplot(mapping=p9.aes(x='Scenario', ymin='ymin', lower='lower', middle='middle', upper='upper', ymax='ymax'), data=df, color='k', show_legend=False, inherit_aes=False)
gg += p9.themes.theme_seaborn()
gg += p9.labels.xlab('Scenario')
gg.save(filename='scenario_boxplot.png', dpi=300)
The documentation at https://plotnine.readthedocs.io/en/stable/generated/plotnine.geoms.geom_boxplot.html#plotnine.geoms.geom_boxplot indicates that the geom_boxplot line of code supplies the required aesthetic parameters to define the box and whiskers.
Running this, however, gives
plotnine.exceptions.PlotnineError: 'stat_boxplot requires the
following missing aesthetics: y'
Why is stat_boxplot being called, with its required aesthetics, not geom_boxplot?
And more importantly, does anybody know how to correct this?
You are using geom_boxplot with stat_boxplot instead of stat_identity.
geom_boxplot(stat='identity', ...)

pymc3 multivariate traceplot color coding

I am new to working with pymc3 and I am having trouble generating an easy-to-read traceplot.
I'm fitting a mixture of 4 multivariate gaussians to some (x, y) points in a dataset. The model runs fine. My question is with regard to manipulating the pm.traceplot() command to make the output more user-friendly.
Here's my code:
import matplotlib.pyplot as plt
import numpy as np
model = pm.Model()
N_CLUSTERS = 4
with model:
#cluster prior
w = pm.Dirichlet('w', np.ones(N_CLUSTERS))
#latent cluster of each observation
category = pm.Categorical('category', p=w, shape=len(points))
#make sure each cluster has some values:
w_min_potential = pm.Potential('w_min_potential', tt.switch(tt.min(w) < 0.1, -np.inf, 0))
#multivariate normal means
mu = pm.MvNormal('mu', [0,0], cov=[[1,0],[0,1]], shape = (N_CLUSTERS,2) )
#break symmetry
pm.Potential('order_mu_potential', tt.switch(
tt.all(
[mu[i, 0] < mu[i+1, 0] for i in range(N_CLUSTERS - 1)]), -np.inf, 0))
#multivariate centers
data = pm.MvNormal('data', mu =mu[category], cov=[[1,0],[0,1]], observed=points)
with model:
trace = pm.sample(1000)
A call to pm.traceplot(trace, ['w', 'mu']) produces this image:
As you can see, it is ambiguous which mean peak corresponds to an x or y value, and which ones are paired together. I have managed a workaround as follows:
from cycler import cycler
#plot the x-means and y-means of our data!
fig, (ax0, ax1) = plt.subplots(nrows=2)
plt.xlabel('$\mu$')
plt.ylabel('frequency')
for i in range(4):
ax0.hist(trace['mu'][:,i,0], bins=100, label='x{}'.format(i), alpha=0.6);
ax1.hist(trace['mu'][:,i,1],bins=100, label='y{}'.format(i), alpha=0.6);
ax0.set_prop_cycle(cycler('color', ['c', 'm', 'y', 'k']))
ax1.set_prop_cycle(cycler('color', ['c', 'm', 'y', 'k']))
ax0.legend()
ax1.legend()
This produces the following, much more legible plot:
I have looked through the pymc3 documentation and recent questions here, but to no avail. My question is this: is it possible to do what I have done here with matplotlib via builtin methods in pymc3, and if so, how?
Better differentiation between multidimensional variables and the different chains was recently added to ArviZ (the library PyMC3 relies on for plotting).
In ArviZ latest version, you should be able to do:
az.plot_trace(trace, compact=True, legend=True)
to get the different dimensions of each variable distinguished by color and the different chains distinguished by linestyle. The default setting is using matplotlib's default color cycle and 4 different linestyles, solid, dashed, dotted and dash-dotted. Both properties can be set to custom aesthetics and custom values by using compact_prop to customize dimension representation and chain_prop to customize chain representation. In addition, if using compact, it may also be a good idea to use combined=True to reduce the clutter in the first column. As an example:
az.plot_trace(trace, compact=True, combined=True, legend=True, chain_prop=("ls", "-"))
would plot the KDEs in the first column using the data from all chains, and would plot all chains using a solid linestyle (due to combined arg, only relevant for the second column). Two legends will be shown, one for the chain info and another for the compact info.
At least in recent versions, you can use compact=True as in:
pm.traceplot(trace, var_names = ['parameters'], compact=True)
to get one graph with all you params combined
Docs in: https://arviz-devs.github.io/arviz/_modules/arviz/plots/traceplot.html
However, I haven't been able to get the colors to differ between lines

Matplotlib 2.0 subscript outside of baseline when super and subscript are both used

With matplotlib 2.0 I have been having strange behavior when I use both subscript and superscript on the same character. When they are combined, the subscript goes down entirely below the baseline. This didn't happen with MPL 1.5. Here is a complete example:
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rc("font", family="Times New Roman",weight='normal')
plt.rcParams.update({'mathtext.default': 'regular' })
plt.plot(1,1, label='$A_x^{b}$')
plt.plot(2,2,label='$A_x$')
plt.plot(3,3,label='$A^b$')
plt.plot(4,4,label='$A_x^{*}$')
plt.plot(5,5,label='$A^*$')
plt.legend(fontsize='xx-large')
plt.show()
I've taken this plot and zoomed in on the legend and drawn some horizontal lines to show the relative super and subscript positions.
I found in the mathtext.py file these parameters under the class FontConstantBase:
# Percentage of x-height of additional horiz. space after sub/superscripts
script_space = 0.05
# Percentage of x-height that sub/superscripts drop below the baseline
subdrop = 0.4
# Percentage of x-height that superscripts are raised from the baseline
sup1 = 0.7
# Percentage of x-height that subscripts drop below the baseline
sub1 = 0.3
# Percentage of x-height that subscripts drop below the baseline when a
# superscript is present
sub2 = 0.5
# Percentage of x-height that sub/supercripts are offset relative to the
# nucleus edge for non-slanted nuclei
delta = 0.025
# Additional percentage of last character height above 2/3 of the
# x-height that supercripts are offset relative to the subscript
# for slanted nuclei
delta_slanted = 0.2
# Percentage of x-height that supercripts and subscripts are offset for
# integrals
delta_integral = 0.1
Did sub2 exist in previous versions? Could going from 0.3 to 0.5 really drop it completely below the baseline like I'm seeing? I'd like to have simultaneous superscripts and subscripts that aren't completely outside the baseline and I don't see any other way besides modifying mathtext.py itself. Also, it appears that when including an asterisk in the superscript, it also goes higher than anticipated with mpl 2.0. Is there a way to lower it down just a bit without changing mathtext? Thanks.
There seems to be no API to change this but you can monkey-patch the appropriate class instead of editing mathtext.py.
Using the default mathtext font the position of the subscript changes if there is a superscript (not totally under the baseline but you can see the effect):
def test_plot():
plt.figure()
plt.plot(1, 1, label="$A_x^b$")
plt.plot(2, 2, label="$A^b_x$")
plt.plot(3, 3, label="$A_x$")
plt.plot(4, 4, label="$A_x^*$")
plt.plot(4, 4, label="$A^*_x$")
plt.plot(5, 5, label="$A^*$")
plt.legend(fontsize="xx-large")
# default mathtext font in matplotlib 2.0.0 is 'dejavusans'
# set explicitly for reproducibility
plt.rcParams["mathtext.fontset"] = "dejavusans"
test_plot()
Monkey-patching mathtext.DejaVuSansFontConstants you can make the effect disappear:
import matplotlib.mathtext as mathtext
mathtext.DejaVuSansFontConstants.sub2 = 0.3 # default 0.5
test_plot()
(For more recent versions of matplotlib, like 3.4.2, this class appears to have been moved to a _mathtext submodule. You may need to do something like the following:)
# Later versions of matplotlib (e.g., 3.4.2)
from matplotlib.mathtext import _mathtext as mathtext
mathtext.FontConstantsBase.sup1 = 0.5
I can't see any issue with the asterisk.
I don't have Times New Roman installed so I can't test your exact use case but probably you need to patch FontConstantsBase instead of DejaVuSansFontConstants. It worked for me using Liberation Serif.

Create a color generator from given colormap in matplotlib

I have a series of lines that each need to be plotted with a separate colour. Each line is actually made up of several data sets (positive, negative regions etc.) and so I'd like to be able to create a generator that will feed one colour at a time across a spectrum, for example the gist_rainbow map shown here.
I have found the following works but it seems very complicated and more importantly difficult to remember,
from pylab import *
NUM_COLORS = 22
mp = cm.datad['gist_rainbow']
get_color = matplotlib.colors.LinearSegmentedColormap.from_list(mp, colors=['r', 'b'], N=NUM_COLORS)
...
# Then in a for loop
this_color = get_color(float(i)/NUM_COLORS)
Moreover, it does not cover the range of colours in the gist_rainbow map, I have to redefine a map.
Maybe a generator is not the best way to do this, if so what is the accepted way?
To index colors from a specific colormap you can use:
import pylab
NUM_COLORS = 22
cm = pylab.get_cmap('gist_rainbow')
for i in range(NUM_COLORS):
color = cm(1.*i/NUM_COLORS) # color will now be an RGBA tuple
# or if you really want a generator:
cgen = (cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS))

Categories

Resources