I am trying to understand the keyword arguments that can be used in matplotlib radviz. I am using the well-known iris dataset, and the simple code below:
import pandas as pd
plt.xkcd()
iris = pd.read_csv("iris.csv")
pd.tools.plotting.radviz(iris, "name")
Generating the following chart:
How can I setup the dimensions (x, y) and the title of the chart? How can I specify the placement of the legend? What other arguments (if any) can be used with radviz?
Thank you very much for your help.
all the pandas plotting tools take an ax argument, you can make the axis and pass to the plotting function:
fig = plt.figure( )
ax = fig.add_axes( [.05, .05, .9, .9], title='whatever title' )
pd.tools.plotting.radviz( iris, 'name', ax=ax )
then if you need to change the legend, you may do:
ax.legend( loc='center right', fontsize='medium' )
or change the title:
ax.set_title( 'new title' )
alternatively, i believe the plotting tools return the axis after plotting, so you may do
ax = pd.tools.plotting.radviz( iris, 'name')
and check dir( ax ) for some of the functionality available.
with plt.xkcd( ):
ax = pd.tools.plotting.radviz(df, 'Name')
ax.legend( loc='center left', bbox_to_anchor=(0, 1),
fontsize='medium', fancybox=True, ncol=3 )
ax.set_xlim( -1.6, 1.6, emit=True, auto=False )
ax.set_title( 'iris - radviz', loc='right' )
Related
I'm using Seaborn to plot a cumulative distribution and it's KDE using this code:
sns.distplot(values, bins=20,
hist_kws= {'cumulative': True},
kde_kws= {'cumulative': True} )
This gives me the following chart:
I'd like to plot a vertical line and the corresponding x index where y is 0.8. Something like:
How do I get the x value of a specific y?
You could draw a vertical line at the 80% quantile:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
values = np.random.normal(1, 20, 1000)
sns.distplot(values, bins=20,
hist_kws= {'cumulative': True},
kde_kws= {'cumulative': True} )
plt.axvline(np.quantile(values, 0.8), color='r')
plt.show()
The answer by #JohanC is probably the best. I went an other route and it's maybe a slightly more generic solution.
The idea is to get the coordinates of the kde line, then find the indice of the point where it crosses the threshold value
values = np.random.normal(size=(100,))
fig = plt.figure()
ax = sns.distplot(values, bins=20,
hist_kws= {'cumulative': True},
kde_kws= {'cumulative': True} )
x,y = ax.lines[0].get_data()
thresh = 0.8
idx = np.where(np.diff(np.sign(y-thresh)))[0]
x_val = x[idx[0]]
ax.axvline(x_val, color='red')
Believe it or not I need help with formatting the title of the legend (not the title of the plot) in a simple plot. I am plotting two series of data (X1 and X2) against Y in a twiny() plot.
I call matplotlib.lines to construct lines for the legend and then call plt.legend to construct a legend pass text strings to name/explain the lines, format that text and place the legend. I could also pass a title-string to plt.legend but I cannot format it.
The closest I have come to a solution is to create another 'artist' for the title using .legend()set_title and then format the title text. I assign it to a variable and call the variable in the above mentioned plt.legend. This does not result in an error nor does it produce the desired effect. I have no control over the placement of the title.
I have read through a number of S-O postings and answers on legend-related issues, looked at the MPL docs, various tutorial type web-pages and even taken a peak at a GIT-hub issue (#10391). Presumably the answer to my question is somewhere in there but not in a format that I have been able to successfully implement.
#Imports
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
import numpy as np
import seaborn as sns
plt.style.use('seaborn')
#Some made up data
y = np.arange(0, 1200, 100)
x1 = (np.log(y+1))
x2 = (2.2*x1)
#Plot figure
fig = plt.figure(figsize = (12, 14))
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()
sy1, sy2 = 'b-', 'r-'
tp, bm = 0, 1100
red_ticks = np.arange(0, 11, 2)
ax1.plot(x1, y, sy1)
ax1.set_ylim(tp, bm)
ax1.set_xlim(0, 10)
ax1.set_ylabel('Distance (m)')
ax1.set_xlabel('Area')
ax1.set_xticks(red_ticks)
blue_ticks = np.arange(0, 22, 4)
ax2.plot(x2, y, sy2)
ax2.set_xlim(0, 20)
ax2.set_xlabel('Volume')
ax2.set_xticks(blue_ticks)
ax2.grid(False)
x1_line = mlines.Line2D([], [], color='blue')
x2_line = mlines.Line2D([], [], color='red')
leg = ax1.legend().set_title('Format Legend Title ?',
prop = {'size': 'large',
'family':'serif',
'style':'italic'})
plt.legend([x1_line, x2_line], ['Blue Model', 'Red Model'],
title = leg,
prop ={'size':12,
'family':'serif',
'style':'italic'},
bbox_to_anchor = (.32, .92))
So what I want is a simple way to control the formatting of both the legend-title and legend-text in a single artist, and also have control over the placement of said legend.
The above code returns a "No handles with labels found to put in legend."
You need one single legend. You can set the title of that legend (not some other legend); then style it to your liking.
leg = ax2.legend([x1_line, x2_line], ['Blue Model', 'Red Model'],
prop ={'size':12, 'family':'serif', 'style':'italic'},
bbox_to_anchor = (.32, .92))
leg.set_title('Format Legend Title ?', prop = {'size': 24, 'family':'sans-serif'})
Unrelated, but also important: Note that you have two figures in your code. You should remove one of them.
I generated a plot with 7 curves and saved it as a Matplotlib Axis object. However, now I want to change the colors in each one of those curves. Since the curves take a while to generate, is it possible to change the colors of these curves from the Axis object itself?
import matplotlib.pyplot as plt
import pickle
import numpy as np
fig, ax = plt.subplots()
x = np.arange(10)
y1 = np.random.random(10)
y2 = np.random.random(10)
kwargs_1 = {
'color': 'red',
'linestyle': ':',
'label': '1',
}
kwargs_2 = {
'color': 'blue',
'linestyle': '--',
'label': '2',
}
ax.plot(x, y1, **kwargs_1)
ax.plot(x, y2, **kwargs_2)
pickle.dump(ax, open('axis_obj.pkl', 'wb'))
plt.clf()
plt.close()
ax_read = pickle.load(open('axis_obj.pkl', 'rb'))
fig = plt.figure()
ax_read.figure = fig
fig.axes.append(ax_read)
fig.add_axes(ax_read)
# and now I'm stuck on how to access the plot kwargs used earlier for this ax_read object
ax.get_lines() is a better way.
You can change the colors by using this code:
# change the color of the plot lines:
ax.properties()['children'][0].set_color('green')
ax.properties()['children'][1].set_color('black')
Explanation: The axes object has the attribute properties which holds the children of the axes object. children is a list containing all objects which were drawn to the axis:
>>> ax.properties()['children']
[
<matplotlib.lines.Line2D at 0x7f2edb896b70>,
<matplotlib.lines.Line2D at 0x7f2edb896ac8>,
...]
The first two elements are the plots which you have drawn to the axis.
I'm facing a problem in showing the legend in the correct format using matplotlib.
EDIT: I have 4 subplots in a figure in 2 by 2 format and I want legend only on the first subplot which has two lines plotted on it. The legend that I got using the code attached below contained endless entries and extended vertically throughout the figure. When I use the same code using linspace to generate fake data the legend works absolutely fine.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
import os
#------------------set default directory, import data and create column output vectors---------------------------#
path="C:/Users/Pacman/Data files"
os.chdir(path)
data =np.genfromtxt('vrp.txt')
x=np.array([data[:,][:,0]])
y1=np.array([data[:,][:,6]])
y2=np.array([data[:,][:,7]])
y3=np.array([data[:,][:,9]])
y4=np.array([data[:,][:,11]])
y5=np.array([data[:,][:,10]])
nrows=2
ncols=2
tick_l=6 #length of ticks
fs_axis=16 #font size of axis labels
plt.rcParams['axes.linewidth'] = 2 #Sets global line width of all the axis
plt.rcParams['xtick.labelsize']=14 #Sets global font size for x-axis labels
plt.rcParams['ytick.labelsize']=14 #Sets global font size for y-axis labels
plt.subplot(nrows, ncols, 1)
ax=plt.subplot(nrows, ncols, 1)
l1=plt.plot(x, y2, 'yo',label='Flow rate-fan')
l2=plt.plot(x,y3,'ro',label='Flow rate-discharge')
plt.title('(a)')
plt.ylabel('Flow rate ($m^3 s^{-1}$)',fontsize=fs_axis)
plt.xlabel('Rupture Position (ft)',fontsize=fs_axis)
# This part is not working
plt.legend(loc='upper right', fontsize='x-large')
#Same code for rest of the subplots
I tried to implement a fix suggested in the following link, however, could not make it work:
how do I make a single legend for many subplots with matplotlib?
Any help in this regard will be highly appreciated.
If I understand correctly, you need to tell plt.legend what to put as legends... at this point it is being loaded empty. What you get must be from another source. I have quickly the following, and of course when I run fig.legend as you do I get nothing.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.1, 0.4, 0.7])
ax2 = fig.add_axes([0.55, 0.1, 0.4, 0.7])
x = np.arange(0.0, 2.0, 0.02)
y1 = np.sin(2*np.pi*x)
y2 = np.exp(-x)
l1, l2 = ax1.plot(x, y1, 'rs-', x, y2, 'go')
y3 = np.sin(4*np.pi*x)
y4 = np.exp(-2*x)
l3, l4 = ax2.plot(x, y3, 'yd-', x, y4, 'k^')
fig.legend(loc='upper right', fontsize='x-large')
#fig.legend((l1, l2), ('Line 1', 'Line 2'), 'upper left')
#fig.legend((l3, l4), ('Line 3', 'Line 4'), 'upper right')
plt.show()
I'd suggest doing one by one, and then applying for all.
It is useful to work with the axes directly (ax in your case) when when working with subplots. So if you set up two plots in a figure and only wish to have a legend in your second plot:
t = np.linspace(0, 10, 100)
plt.figure()
ax1 = plt.subplot(2, 1, 1)
ax1.plot(t, t * t)
ax2 = plt.subplot(2, 1, 2)
ax2.plot(t, t * t * t)
ax2.legend('Cubic Function')
Note that when creating the legend, I am doing so on ax2 as opposed to plt. If you wish to create a second legend for the first subplot, you can do so in the same way but on ax1.
This is similar to Matlab: Combine the legends of shaded error and solid line mean, except for Matplotlib. Example code:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([0,1])
y = x + 1
f,a = plt.subplots()
a.fill_between(x,y+0.5,y-0.5,alpha=0.5,color='b')
a.plot(x,y,color='b',label='Stuff',linewidth=3)
a.legend()
plt.show()
The above code produces a legend that looks like this:
How can I create a legend entry that combines the shading from fill_between and the line from plot, so that it looks something like this (mockup made in Gimp):
MPL supports tuple inputs to legend so that you can create composite legend entries (see the last figure on this page). However, as of now PolyCollections--which fill_between creates/returns--are not supported by legend, so simply supplying a PolyCollection as an entry in a tuple to legend won't work (a fix is anticipated for mpl 1.5.x).
Until the fix arrives I would recommend using a proxy artist in conjunction with the 'tuple' legend entry functionality. You could use the mpl.patches.Patch interface (as demonstrated on the proxy artist page) or you could just use fill. e.g.:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([0, 1])
y = x + 1
f, a = plt.subplots()
a.fill_between(x, y + 0.5, y - 0.5, alpha=0.5, color='b')
p1 = a.plot(x, y, color='b', linewidth=3)
p2 = a.fill(np.NaN, np.NaN, 'b', alpha=0.5)
a.legend([(p2[0], p1[0]), ], ['Stuff'])
plt.show()