Row Titles within a matplotlib GridSpec - python

I have an GridSpec defined layout with to subgrids, one is supposed to include a colorbar
import pylab as plt
import numpy as np
gs_outer = plt.GridSpec(1, 2, width_ratios=(10, 1))
gs_inner = plt.matplotlib.gridspec.GridSpecFromSubplotSpec(2, 3, gs_outer[0])
ax = []
for i in xrange(6):
ax.append(plt.subplot(gs_inner[i]))
plt.setp(ax[i].get_xticklabels(), visible=False)
plt.setp(ax[i].get_yticklabels(), visible=False)
ax.append(plt.subplot(gs_outer[1]))
plt.show()
I'd now like to get for the left part a row-wise labeling like this:
I tried to add another GridSpec into the GridSpec, but that did not work out:
import pylab as plt
import numpy as np
fig = plt.figure()
gs_outer = plt.GridSpec(1, 2, width_ratios=(10, 1))
gs_medium = plt.matplotlib.gridspec.GridSpecFromSubplotSpec(3, 1, gs_outer[0])
ax_title0 = plt.subplot(gs_medium[0])
ax_title0.set_title('Test!')
gs_row1 = plt.matplotlib.gridspec.GridSpecFromSubplotSpec(1, 3, gs_medium[0])
ax00 = plt.subplot(gs_row1[0]) # toggle this line to see the effect
plt.show()
Adding the ax00 = plt.subplot... line seems to erase the previously created axis

Following CT Zhu comment I came up with the following answer (I don't really like it, but it seems to work)
import pylab as plt
import numpy as np
fig = plt.figure()
rows = 2
cols = 3
row_fraction = 9
row_size = row_fraction / float(rows)
gs_outer = plt.GridSpec(1,2, width_ratios=(9,1))
gs_plots= plt.matplotlib.gridspec.GridSpecFromSubplotSpec(rows * 2, cols, subplot_spec=gs_outer[0], height_ratios = rows * [1, row_size])
# Create title_axes
title_ax = []
for ta in xrange(rows):
row_index = (ta) * 2
title_ax.append(plt.subplot(gs_plots[row_index, :]))
# Create Data axes
ax = []
for row in xrange(rows):
row_index = (row + 1) * 2 -1
for col in xrange(cols):
try:
ax.append(plt.subplot(gs_plots[row_index, col], sharex=ax[0], sharey=ax[0]))
except IndexError:
if row == 0 and col == 0:
ax.append(plt.subplot(gs_plots[row_index, col]))
else:
raise IndexError
# Delete Boxes and Markers from title axes
for ta in title_ax:
ta._frameon = False
ta.xaxis.set_visible(False)
ta.yaxis.set_visible(False)
# Add labels to title axes:
for ta, label in zip(title_ax, ['Row 1', 'Row 2']):
plt.sca(ta)
plt.text(
0.5, 0.5, label, horizontalalignment='center', verticalalignment='center')
# Add common colorbar
gs_cb = plt.matplotlib.gridspec.GridSpecFromSubplotSpec(
1, 1, subplot_spec=gs_outer[1])
ax.append(plt.subplot(gs_cb[:, :]))
Of course labeling and ticklabels could be improved. But how to achive that is likely already explained on SO.

Let's define an example grid pltgrid:
pltgrid = gridspec.GridSpec(ncols=3, nrows=2,
width_ratios=[1]*3, wspace=0.3,
hspace=0.6, height_ratios=[1]*2)
Before your for loop, you can define a list ax using map:
num=list(range(7))
ax=list(map(lambda x : 'ax'+str(x), num))
You may have a list plotnames containing the names. As an example, I'll plot a normal distribution Q-Q plot for each i in the for loop:
for i in xrange(6):
ax[i]=fig.add.subplot(pltgrid[i])
res = stats.probplot(x, dist="norm", plot=ax[i])
# set title for subplot using existing 'plotnames' list
ax[i].set_title(plotnames[i])
# display subplot
ax[i]

Related

How to set matplotlib's shared subplots legend to be horizontal and at lower center position?

I'm using Matplotlib and Seaborn to plot four bar graphs with one shared legend. However, I can't make the legend to be horizontal and at the lower center. I tried to set the numbers in this line:
ax.legend(bbox_to_anchor=(0.99, -0.15),
loc=1,
fontsize=13,
# ncol=2
)
but if the legend goes to the middle, then the distance between the two subplot columns would increase as well making it not good.
Here is my code:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import pdb
import pyautogui
import multiprocessing
from time import sleep
from matplotlib import patches as mpatches
def convert_to_grouped_bar_chart_format(data,
col_1_name, col_2_name, col_3_name):
"""
Parameters
----------
data: Pandas dataframe. Format:
Method Class1 Class2 Class3
0 Method_1 0.1 0.2 0.3
1 Method_2 0.6 0.5 0.4
Returns
-------
data_grouped: Pandas dataframe.
"""
cls_list = data.columns[1:].tolist()
col_1 = []
col_2 = []
col_3 = []
(num_of_rows, num_of_cols) = data.shape
for row_idx in range(num_of_rows):
for cls_idx, cls in enumerate(cls_list):
col_1.append(data.iloc[row_idx, 0])
col_2.append(cls)
col_3.append(data.iloc[row_idx, cls_idx+1])
pass
pass
data_grouped_dict = {
col_1_name: col_1,
col_2_name: col_2,
col_3_name: col_3
}
data_grouped = pd.DataFrame(data_grouped_dict, columns = [col_1_name, col_2_name, col_3_name])
return data_grouped
def draw_four_bar_graph_seaborn():
file_list = [
['Measure1_ED.csv', 'Measure1_ES.csv'],
['Measure2_ED.csv', 'Measure2_ES.csv']
]
n_rows = len(file_list)
n_cols = len(file_list[0])
fig, axes = plt.subplots(n_rows, n_cols)
for idx_row in range(n_rows):
# if idx_row > 0:
# continue
for idx_col in range(n_cols):
file_name = file_list[idx_row][idx_col]
data = pd.read_csv(file_name)
col_1_name = 'Method'
col_2_name = 'Class'
col_3_name = file_name.split('_')[0]
data_type = file_name.split('_')[1][:-4]
ax = axes[idx_row, idx_col]
# ax =axes[idx_col]
data_grouped = convert_to_grouped_bar_chart_format(data,
col_1_name, col_2_name, col_3_name)
splot = sns.barplot(
# ax=axes[idx_row, idx_col],
ax=ax,
x=col_2_name,
y=col_3_name,
hue=col_1_name,
palette="magma",
# palette=my_pal,
# sharey=False,
data=data_grouped)
splot.set_xlabel("",fontsize=1)
splot.set_ylabel(col_3_name,fontsize=13)
splot.tick_params(labelsize=13)
title_subplot = 'Title 1'
ax.set_title(title_subplot, fontsize=13)
if col_3_name == 'Measure1':
ax.set_ylim(0, 1.10)
else:
ax.set_ylim(0, 2.25)
for p1 in splot.patches:
splot.annotate('%.3f' % p1.get_height(),
(p1.get_x() + p1.get_width() / 2., p1.get_height()),
ha = 'center', va = 'center',
size=13,
xytext = (0, 8),
textcoords = 'offset points')
if (idx_row == 1) and (idx_col == 0):
ax.legend(
bbox_to_anchor=(1.2, -0.15),
loc=1,
fontsize=13,
# ncol=2
)
else:
splot.get_legend().remove()
# Change width size
# ax = axes[idx_row, idx_col]
new_value = 0.35
for patch in ax.patches :
current_width = patch.get_width()
diff = current_width - new_value
# we change the bar width
patch.set_width(new_value)
# we recenter the bar
patch.set_x(patch.get_x() + diff * .5)
plt.tight_layout(pad=0)
mng = plt.get_current_fig_manager()
mng.window.state('zoomed') #works fine on Windows!
plt.show()
fig.savefig('out.pdf')
plt.close()
def draw_graph_then_save_and_close_automatically(func=None, args=[]):
coords_close_graph = (1365, 12) # Auto click to close graph
multiprocessing.Process(target=func, args=args).start()
sleep(10)
pyautogui.moveTo(coords_close_graph)
pyautogui.click()
def main():
draw_graph_then_save_and_close_automatically(
func=draw_four_bar_graph_seaborn,
args=[])
if __name__ == '__main__':
main()
Please help me, thank you very much.
Use a figure-legend instead of place on on one of your axes and set the number of columns that the legend should have to the number of legend entries. Here is an example (I did find your's to be minimal enough^^)
import numpy as np
from matplotlib import pyplot as plt
# create random data
y = np.random.randint(0,100,size=(10, 3))
# open a figure with two axes
fig,axs = plt.subplots(1,2)
# plot something in the axes
axs[0].plot(y[:,0])
axs[1].plot(y[:,1:])
# define the name of the
legendEntries = ("a","bcdefg","h")
# set figure legend entries, number of columns, location
fig.legend(legendEntries,ncol=len(legendEntries),loc="upper center")
Here is a doc-example, emphasizing to use the argument ncol to force matplotlib to expand the legend horizontally. And here is a tutorial/example how you can place the legend of an axis outside the region of the axis.

Tick labels appearing twice

I am trying to create a figure that is a dendrogram on top of a scatterplot, where the ends of the leaves on the dendrogram match up with the dots on the scatterplot, which in turn match up with the tick labels below. I have this working, but for some reason the tick labels appear twice. The labels in red and green are the ones I'm trying to keep.
This is my code:
import pandas as pd
from matplotlib import pyplot as plt
import scipy.cluster.hierarchy as sch
import numpy as np
import json
import random
def scatter_and_dendrogram(df, colors,wn='',label_x=False):
'''Args:
df (Pandas DataFrame): similarity matrix
colors (list of strs): list of colors
wn (str): window name
label_x=False(Bool): whether or not to label x axis
Returns: None
'''
norm = plt.Normalize(1,4)
dist_matrix = [] #linkage
for i in range(len(df)):
arr = []
for j in range(1,len(df.iloc[i])):
arr.append(df.iloc[i,j])
dist_matrix.append(list(arr))
X = np.asarray(dist_matrix)
Z = sch.linkage(X, 'ward')
sch.set_link_color_palette(['b'])
fig = plt.figure()
fig, axs = plt.subplots(2, 1, sharex='col', sharey='row',
gridspec_kw={'width_ratios': [1],
'height_ratios': [30, 1],
'hspace': 0, 'wspace': 0})
(ax1, ax2) = axs
dendrogram = sch.dendrogram(Z=Z, p=3,ax=ax1)
icoords = dendrogram['icoord']
dcoords = dendrogram['dcoord']
lst = [[],[],colors]
for i in range(len(icoords)):
ic = icoords[i]
dc = dcoords[i]
if dc.count(0) == 2:
lst[0].append(ic[0])
lst[0].append(ic[-1])
elif dc.count(0) == 1:
ind = dc.index(0)
lst[0].append(ic[ind])
lst[1] = [-0.1]*len(lst[0])
ax2.scatter(lst[0],lst[1],s=10,norm=norm, alpha=0.7)
fig.canvas.set_window_title(wn)
ax1.set_yticklabels([])
ax1.set_xticklabels([])
ax2.set_yticklabels([])
ax2.set_xticklabels([])
if label_x:
letters = list('ABCD')
labels = [letters[ind] for ind in dendrogram['leaves']]
c1 = '#ff0033' #red
c2 = '#006600'#green
xlbls = ax2.set_xticklabels(labels,fontsize=11,linespacing=3)
for lbl in xlbls:
t = lbl.get_text()
c = c2
if letters.index(t) < 2:
c = c1
print(c)
lbl.set_color(c)
ax1.set_title(wn)
ax1.set_ylabel('Aggregation Criterion',fontsize=15)
ax2.set_xlabel('Articles', fontsize=15)
plt.show()
l = ['A','B','C','D']
df = pd.DataFrame(index=l, columns=l)
for i in range(len(l)-1):
for j in range(i+1, len(l)):
r = random.randint(0, 10)
df.iloc[i,j] = r
df.iloc[j, i] = r
df.fillna(0,inplace=True)
print(df)
wn = 'Set C'
scatter_and_dendrogram(df, l, wn,True)
This is what it looks like:
According to matplotlib.pyplot.subplots about sharex and sharey
When subplots have a shared x-axis along a column, only the x tick
labels of the bottom subplot are created.
Similarly, when subplots have a shared y-axis along a row, only the y tick labels of the first column subplot are created.
To later turn other subplots' ticklabels on, use tick_params.
You need to add ax1.tick_params(axis='x', labelbottom=False) under xlbls = ax2.set_xticklabels.
Besides, if fig = plt.figure() is useless, remove it.

How to plot an animated matrix in matplotlib

I need to do step by step some numerical calculation algorithms visually, as in the figure below: (gif)
Font
How can I do this animation with matplotlib? Is there any way to visually present these transitions? As transformation of matrices, sum, transposition, using a loop and it presenting the transitions etc.
My goal is not to use graphics but the same matrix representation. This is to facilitate the understanding of the algorithms.
Since matrices can be plotted easily with imshow, one could create such table with an imshow plot and adjust the data according to the current animation step.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import matplotlib.animation
#####################
# Array preparation
#####################
#input array
a = np.random.randint(50,150, size=(5,5))
# kernel
kernel = np.array([[ 0,-1, 0], [-1, 5,-1], [ 0,-1, 0]])
# visualization array (2 bigger in each direction)
va = np.zeros((a.shape[0]+2, a.shape[1]+2), dtype=int)
va[1:-1,1:-1] = a
#output array
res = np.zeros_like(a)
#colorarray
va_color = np.zeros((a.shape[0]+2, a.shape[1]+2))
va_color[1:-1,1:-1] = 0.5
#####################
# Create inital plot
#####################
fig = plt.figure(figsize=(8,4))
def add_axes_inches(fig, rect):
w,h = fig.get_size_inches()
return fig.add_axes([rect[0]/w, rect[1]/h, rect[2]/w, rect[3]/h])
axwidth = 3.
cellsize = axwidth/va.shape[1]
axheight = cellsize*va.shape[0]
ax_va = add_axes_inches(fig, [cellsize, cellsize, axwidth, axheight])
ax_kernel = add_axes_inches(fig, [cellsize*2+axwidth,
(2+res.shape[0])*cellsize-kernel.shape[0]*cellsize,
kernel.shape[1]*cellsize,
kernel.shape[0]*cellsize])
ax_res = add_axes_inches(fig, [cellsize*3+axwidth+kernel.shape[1]*cellsize,
2*cellsize,
res.shape[1]*cellsize,
res.shape[0]*cellsize])
ax_kernel.set_title("Kernel", size=12)
im_va = ax_va.imshow(va_color, vmin=0., vmax=1.3, cmap="Blues")
for i in range(va.shape[0]):
for j in range(va.shape[1]):
ax_va.text(j,i, va[i,j], va="center", ha="center")
ax_kernel.imshow(np.zeros_like(kernel), vmin=-1, vmax=1, cmap="Pastel1")
for i in range(kernel.shape[0]):
for j in range(kernel.shape[1]):
ax_kernel.text(j,i, kernel[i,j], va="center", ha="center")
im_res = ax_res.imshow(res, vmin=0, vmax=1.3, cmap="Greens")
res_texts = []
for i in range(res.shape[0]):
row = []
for j in range(res.shape[1]):
row.append(ax_res.text(j,i, "", va="center", ha="center"))
res_texts.append(row)
for ax in [ax_va, ax_kernel, ax_res]:
ax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)
ax.yaxis.set_major_locator(mticker.IndexLocator(1,0))
ax.xaxis.set_major_locator(mticker.IndexLocator(1,0))
ax.grid(color="k")
###############
# Animation
###############
def init():
for row in res_texts:
for text in row:
text.set_text("")
def animate(ij):
i,j=ij
o = kernel.shape[1]//2
# calculate result
res_ij = (kernel*va[1+i-o:1+i+o+1, 1+j-o:1+j+o+1]).sum()
res_texts[i][j].set_text(res_ij)
# make colors
c = va_color.copy()
c[1+i-o:1+i+o+1, 1+j-o:1+j+o+1] = 1.
im_va.set_array(c)
r = res.copy()
r[i,j] = 1
im_res.set_array(r)
i,j = np.indices(res.shape)
ani = matplotlib.animation.FuncAnimation(fig, animate, init_func=init,
frames=zip(i.flat, j.flat), interval=400)
ani.save("algo.gif", writer="imagemagick")
plt.show()
This example sets up the animation inline in a Jupyter notebook. I suppose there's probably also a way to export as a gif, but I haven't looked into that so far.
Anyway, first thing to do is set up the table. I borrowed heavily from Export a Pandas dataframe as a table image for the render_mpl_table code.
The (adapted) version for this problem is:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
from IPython.display import HTML
import six
width = 8
data = pd.DataFrame([[0]*width,
[0, *np.random.randint(95,105,size=width-2), 0],
[0, *np.random.randint(95,105,size=width-2), 0],
[0, *np.random.randint(95,105,size=width-2), 0]])
def render_mpl_table(data, col_width=3.0, row_height=0.625, font_size=14,
row_color="w", edge_color="black", bbox=[0, 0, 1, 1],
ax=None, col_labels=data.columns,
highlight_color="mediumpurple",
highlights=[], **kwargs):
if ax is None:
size = (np.array(data.shape[::-1]) + np.array([0, 1])) *
np.array([col_width, row_height])
fig, ax = plt.subplots(figsize=size)
ax.axis('off')
mpl_table = ax.table(cellText=data.values, bbox=bbox, colLabels=col_labels,
**kwargs)
mpl_table.auto_set_font_size(False)
mpl_table.set_fontsize(font_size)
for k, cell in six.iteritems(mpl_table._cells):
cell.set_edgecolor(edge_color)
if k in highlights:
cell.set_facecolor(highlight_color)
elif data.iat[k] > 0:
cell.set_facecolor("lightblue")
else:
cell.set_facecolor(row_color)
return fig, ax, mpl_table
fig, ax, mpl_table = render_mpl_table(data, col_width=2.0, col_labels=None,
highlights=[(0,2),(0,3),(1,2),(1,3)])
In this case, the cells to highlight in a different color are given by an array of tuples that specify the row and column.
For the animation, we need to set up a function that draws the table with different highlights:
def update_table(i, *args, **kwargs):
r = i//(width-1)
c = i%(width-1)
highlights=[(r,c),(r,c+1),(r+1,c),(r+1,c+1)]
for k, cell in six.iteritems(mpl_table._cells):
cell.set_edgecolor("black")
if k in highlights:
cell.set_facecolor("mediumpurple")
elif data.iat[k] > 0:
cell.set_facecolor("lightblue")
else:
cell.set_facecolor("white")
return (mpl_table,)
This forcibly updates the colors for all cells in the table. The highlights array is computed based on the current frame. The width and height of the table are kind of hard-coded in this example, but that shouldn't be super hard to change based on the shape of your input data.
We create an animation based on the existing fig and update function:
a = animation.FuncAnimation(fig, update_table, (width-1)*3,
interval=750, blit=True)
And lastly we show it inline in our notebook:
HTML(a.to_jshtml())
I put this together in a notebook on github, see https://github.com/gurudave/so_examples/blob/master/mpl_animation.ipynb
Hope that's enough to get you going in the right direction!

Making iterative subplots in one subplot2grid

I would like to have a window that is divided in 4 sectors: in the (0,0) a imshow image (ax1); (1,0) a subplot image that uses twinx() image that divides the window(ax2 & ax3); (1,1) a regular plot image (ax4); and an iterative section (0,1) of plots that should give "number_of_subplots" plots one above the other (ax5). Hopefully with no xticklabels but the last one.
This is how the frame should look like before the iterative subplot creation.
My problem: when iterating to create the subplots on the top right space of the window, the subplots span away from that space and eliminate the ax4
This is how the window looks after the "for" cyle for the subplot creation
Below you'll find a simplification of the code I am using, just so you can see it better. I have replaced my experimental data with random numbers so you can replicate this easily.
Could you give me a hint on what am I doing wrong? I still do not dominate all the handlers in python. I used to do similar things in matlab a few years ago.
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import numpy as np
import pdb
pos = [1,2,3,4,5]
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
xx = np.linspace(0, 20, 1000)
fig1 = plt.figure()
number_of_subplots = len(pos) #number between 1-7
ax1 = plt.subplot2grid((number_of_subplots+1,2),(0,0),rowspan = number_of_subplots-1) # Here the idea is to "dinamically" create the division of the grid, making space at the bottom of it for the image in the bottom left.
ax1.scatter(x,y)
ax2 = plt.subplot2grid((number_of_subplots+1,2),(number_of_subplots-1,0), rowspan = 2)
ax2.plot(xx,np.sin(xx),label = 'sin(x)',color = 'b')
ax3 = ax2.twinx()
ax3.plot(xx,np.cos(xx), label = 'cos(x)', color = 'r')
ax4 = plt.subplot2grid((number_of_subplots+1,2),(number_of_subplots-1,1), rowspan = 2)
ax4.plot(xx,np.tan(xx), label = 'tan(x)', color = 'g')
for i,v in enumerate(xrange(number_of_subplots)):
v = v+1
ax5 = plt.subplot2grid((number_of_subplots+1,2),(v-1,1))
ax5.plot(np.sin(xx+3.1416*v/2)) # Grafica los perfiles, asociandoles el mismo color que para los cortes en la imagen 2D
if (i % 2 == 0): #Even
ax5.yaxis.tick_left()
else:
ax5.yaxis.tick_right()
plt.draw()
plt.show()
Solved the issue by using GridSpec as it is supposed to be used. Below is the implementation of the code that gives the following solution.
This is the correct way the image should look like and the implementation is below on the code.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
import pdb
pos = [1,2,3,4,5]
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
xx = np.linspace(0, 20, 1000)
number_of_subplots = len(pos) #number between 1-7
fig1 = plt.figure()
gs0 = gridspec.GridSpec(2,2,height_ratios=[3,1],hspace=0.1)
ax1 = plt.subplot(gs0[0,0])
ax2 = plt.subplot(gs0[-1,0])
ax4 = plt.subplot(gs0[-1,-1])
gs2 = gridspec.GridSpecFromSubplotSpec(number_of_subplots, 1, subplot_spec=gs0[1],wspace=0.0, hspace=0.0)
ax1.scatter(x,y)
ax2.plot(xx,np.sin(xx),label = 'sin(x)',color = 'b')
ax3 = ax2.twinx()
ax3.plot(xx,np.cos(xx), label = 'cos(x)', color = 'r')
ax4.plot(xx,np.tan(xx), label = 'tan(x)', color = 'g')
for i in enumerate(xrange(number_of_subplots)):
ax5 = plt.subplot(gs2[i,:])
ax5.plot(np.sin(xx+3.1416*i/2))
if (i % 2 == 0): #Even
ax5.yaxis.tick_left()
else:
ax5.yaxis.tick_right()
plt.draw()
plt.show()

How should I pass a matplotlib object through a function; as Axis, Axes or Figure?

Sorry in advance if this is a little long winded but if I cut it down too much the problem is lost. I am trying to make a module on top of pandas and matplotlib which will give me the ability to make profile plots and profile matrices analogous to scatter_matrix. I am pretty sure my problem comes down to what object I need to return from Profile() so that I can handle Axes manipulation in Profile_Matrix(). Then the question is what to return form Profile_Matrix() so I can edit subplots.
My module (ProfileModule.py) borrows a lot from https://github.com/pydata/pandas/blob/master/pandas/tools/plotting.py and looks like:
import pandas as pd
from pandas import Series, DataFrame
import numpy as np
import matplotlib.pyplot as plt
def Profile(x,y,nbins,xmin,xmax):
df = DataFrame({'x' : x , 'y' : y})
binedges = xmin + ((xmax-xmin)/nbins) * np.arange(nbins+1)
df['bin'] = np.digitize(df['x'],binedges)
bincenters = xmin + ((xmax-xmin)/nbins)*np.arange(nbins) + ((xmax-xmin)/(2*nbins))
ProfileFrame = DataFrame({'bincenters' : bincenters, 'N' : df['bin'].value_counts(sort=False)},index=range(1,nbins+1))
bins = ProfileFrame.index.values
for bin in bins:
ProfileFrame.ix[bin,'ymean'] = df.ix[df['bin']==bin,'y'].mean()
ProfileFrame.ix[bin,'yStandDev'] = df.ix[df['bin']==bin,'y'].std()
ProfileFrame.ix[bin,'yMeanError'] = ProfileFrame.ix[bin,'yStandDev'] / np.sqrt(ProfileFrame.ix[bin,'N'])
fig = plt.figure();
ax = ProfilePlot.add_subplot(1, 1, 1)
plt.errorbar(ProfileFrame['bincenters'], ProfileFrame['ymean'], yerr=ProfileFrame['yMeanError'], xerr=(xmax-xmin)/(2*nbins), fmt=None)
return ax
#or should I "return fig"
def Profile_Matrix(frame):
import pandas.core.common as com
import pandas.tools.plotting as plots
from pandas.compat import lrange
from matplotlib.artist import setp
range_padding=0.05
df = frame._get_numeric_data()
n = df.columns.size
fig, axes = plots._subplots(nrows=n, ncols=n, squeeze=False)
# no gaps between subplots
fig.subplots_adjust(wspace=0, hspace=0)
mask = com.notnull(df)
boundaries_list = []
for a in df.columns:
values = df[a].values[mask[a].values]
rmin_, rmax_ = np.min(values), np.max(values)
rdelta_ext = (rmax_ - rmin_) * range_padding / 2.
boundaries_list.append((rmin_ - rdelta_ext, rmax_+ rdelta_ext))
for i, a in zip(lrange(n), df.columns):
for j, b in zip(lrange(n), df.columns):
ax = axes[i, j]
common = (mask[a] & mask[b]).values
nbins = 100
(xmin,xmax) = boundaries_list[i]
ax=Profile(df[b][common],df[a][common],nbins,xmin,xmax)
#Profile(df[b][common].values,df[a][common].values,nbins,xmin,xmax)
ax.set_xlabel('')
ax.set_ylabel('')
plots._label_axis(ax, kind='x', label=b, position='bottom', rotate=True)
plots._label_axis(ax, kind='y', label=a, position='left')
if j!= 0:
ax.yaxis.set_visible(False)
if i != n-1:
ax.xaxis.set_visible(False)
for ax in axes.flat:
setp(ax.get_xticklabels(), fontsize=8)
setp(ax.get_yticklabels(), fontsize=8)
return axes
This will run with something like:
import pandas as pd
from pandas import Series, DataFrame
import numpy as np
import matplotlib.pyplot as plt
import ProfileModule as pm
x = np.random.uniform(0, 100, size=1000)
y = x *x + 50*x*np.random.randn(1000)
z = x *y + 50*y*np.random.randn(1000)
nbins = 25
xmax = 100
xmin = 0
ProfilePlot = pm.Profile(x,y,nbins,xmin,xmax)
plt.title("Look this works!")
#This does not work as expected
frame = DataFrame({'z' : z,'x' : x , 'y' : y})
ProfileMatrix = pm.Profile_Matrix(frame)
plt.show()
This would hopefully produce a simple profile plot and a 3x3 profile matrix but it does not. I have tried various different methods to get this to work but I imagine it is not worth explaining them all.
I should mention I am using Enthought Canopy Express on Windows 7. Sorry for the long post and thanks again for any help with the code. This is my first week using Python.
You should pass around Axes objects and break your functions up to operate on a single axes at a time. You are close, but just change
import numpy as np
import matplotlib.pyplot as plt
def _profile(ax, x, y):
ln, = ax.plot(x, y)
# return the Artist created
return ln
def profile_matrix(n, m):
fig, ax_array = plt.subplots(n, m, sharex=True, sharey=True)
for ax in np.ravel(ax_array):
_profile(ax, np.arange(50), np.random.rand(50))
profile_matrix(3, 3)

Categories

Resources