Skip to content
Snippets Groups Projects
Commit d15ee203 authored by Julian Lenz's avatar Julian Lenz
Browse files

TableLegend introduced

parent 8e4cb53c
No related branches found
No related tags found
No related merge requests found
0 1.2149107 0.0022803943
1 0.36490734 0.0022071876
2 0.19920419 0.0021354823
3 0.17301489 0.0024183432
4 0.14481178 0.0022504846
5 0.13120694 0.0030927338
6 0.11904617 0.0031965221
7 0.11141452 0.0031852647
8 0.10413319 0.0037470543
9 0.097506049 0.004300085
10 0.088908326 0.0044386228
11 0.086886814 0.0045989369
12 0.08140338 0.0041411525
13 0.075951132 0.0047760861
14 0.07060553 0.0050090242
15 0.068458513 0.005207937
16 0.066645092 0.0056518971
17 0.066040437 0.0059699327
18 0.063408173 0.0061042218
19 0.062679959 0.0061073468
20 0.0604173 0.0064443888
21 0.058635558 0.0066564646
22 0.057912176 0.0062955945
23 0.05735005 0.0068073894
24 0.054726788 0.0067878676
25 0.052029028 0.0064445648
26 0.05060612 0.0067141805
27 0.050442074 0.0072075856
28 0.049695289 0.0070674233
29 0.049324339 0.0073716488
30 0.048394753 0.0071244185
31 0.049679062 0.007374001
32 0.049679062 0.007374001
33 0.048394753 0.0071244185
34 0.049324339 0.0073716488
35 0.049695289 0.0070674233
36 0.050442074 0.0072075856
37 0.05060612 0.0067141805
38 0.052029028 0.0064445648
39 0.054726788 0.0067878676
40 0.05735005 0.0068073894
41 0.057912176 0.0062955945
42 0.058635558 0.0066564646
43 0.0604173 0.0064443888
44 0.062679959 0.0061073468
45 0.063408173 0.0061042218
46 0.066040437 0.0059699327
47 0.066645092 0.0056518971
48 0.068458513 0.005207937
49 0.07060553 0.0050090242
50 0.075951132 0.0047760861
51 0.08140338 0.0041411525
52 0.086886814 0.0045989369
53 0.088908326 0.0044386228
54 0.097506049 0.004300085
55 0.10413319 0.0037470543
56 0.11141452 0.0031852647
57 0.11904617 0.0031965221
58 0.13120694 0.0030927338
59 0.14481178 0.0022504846
60 0.17301489 0.0024183432
61 0.19920419 0.0021354823
62 0.36490734 0.0022071876
63 1.2149107 0.0022803943
0 1.1872826 0.00052842385
1 0.29534931 0.00043810459
2 0.10548045 0.00043365681
3 0.057842662 0.00043129675
4 0.029525208 0.00043551069
5 0.017239888 0.00043631807
6 0.0098906772 0.0004111901
7 0.0062455619 0.00043630665
8 0.0041741439 0.00042076581
9 0.0027813246 0.0004160544
10 0.0021780028 0.00041260313
11 0.0012655647 0.00042474971
12 0.0012251376 0.00044383005
13 0.0013592305 0.00043513731
14 0.0010687708 0.0004327256
15 0.0015261315 0.00043322977
16 0.0011999303 0.00043310699
17 0.0016298903 0.00042137023
18 0.001541689 0.00042412767
19 0.00067674938 0.00043525081
20 0.0006883261 0.0004179922
21 0.00065868122 0.00043488431
22 0.00014440604 0.0004341915
23 -0.00046178701 0.00042080257
24 -0.0004706054 0.00044694217
25 -0.00044468305 0.00044353051
26 -9.0792861e-05 0.0004387947
27 0.00019907 0.00042506002
28 0.00093792745 0.00044983557
29 0.00098446074 0.00046352933
30 0.00073267069 0.00048768787
31 -0.00011735743 0.00053444699
32 -0.00011735743 0.00053444699
33 0.00073267069 0.00048768787
34 0.00098446074 0.00046352933
35 0.00093792745 0.00044983557
36 0.00019907 0.00042506002
37 -9.0792861e-05 0.0004387947
38 -0.00044468305 0.00044353051
39 -0.0004706054 0.00044694217
40 -0.00046178701 0.00042080257
41 0.00014440604 0.0004341915
42 0.00065868122 0.00043488431
43 0.0006883261 0.0004179922
44 0.00067674938 0.00043525081
45 0.001541689 0.00042412767
46 0.0016298903 0.00042137023
47 0.0011999303 0.00043310699
48 0.0015261315 0.00043322977
49 0.0010687708 0.0004327256
50 0.0013592305 0.00043513731
51 0.0012251376 0.00044383005
52 0.0012655647 0.00042474971
53 0.0021780028 0.00041260313
54 0.0027813246 0.0004160544
55 0.0041741439 0.00042076581
56 0.0062455619 0.00043630665
57 0.0098906772 0.0004111901
58 0.017239888 0.00043631807
59 0.029525208 0.00043551069
60 0.057842662 0.00043129675
61 0.10548045 0.00043365681
62 0.29534931 0.00043810459
63 1.1872826 0.00052842385
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 30 12:15:32 2020
@author: lenz
"""
import numpy as np
from scipy.optimize import curve_fit as fit
import pyVis
pyVis.styling.defaultStyling()
'''
===============================================================================
TableLegend:
This allows to create the legend in a table form. This is convenient, if the
plots are related to each other in a specific way. In the following example,
we show data for various data points and fit through each of the data sets
individually. A standard legend would be very inconvenient because there
would be either a lot of redundancy or ambiguity in the labelling.
CAUTION: At the current stage not all convenience functionality of matplotlib's
original legend() call is implemented. In particular, you have to specify
the labels by hand! Therefore, you should usually also keep track of the
handles yourself, though, in principle, it can figure out the handles for you.
===============================================================================
'''
def cosh2(x,a,m,a2,m2):
return a*np.cosh(m*(x-L/2))+ a2*np.cosh(m2*(x-L/2)/L)
mus=[.0,.0]
nts=[4,16]
ns=63
sigma0=.41
L=ns*sigma0
d1=pyVis.Data1D(overallDirectory='results',
entries={'c':'SpatBosCorr'},
var={'lambd':0,'mu':1,'nt':2},
selection=[{'mu':mus,'nt':nts}])
handles=[]
labels=[]
f,a=pyVis.newFig(name='highT_C')
for mu,nt in zip(mus,nts):
x,y,yerr=d1.get('c',mu=mu,nt=nt).to_numpy()[[0,1,2]]
x*=sigma0
y=y/sigma0**2
yerr=yerr/sigma0**2
T=1/nt/sigma0
parText='$T/\sigma_0={:.3f}$,\n$\mu/\sigma_0={:.2f}$'.format(T,mu/sigma0)
labels.append(('data',parText))
test=a.errorbar(x,y,yerr,
withLines=False,
alpha=.3,
)[0]
handles.append(test)
mask=np.ones_like(x,dtype=bool)
mask[:3]=False
mask[-3:]=False
p,pe=fit(cosh2,x[mask],y[mask],sigma=yerr[mask],
p0=(10**(-8),.1,.00001,.01),
maxfev=10**4)
xGrid=np.linspace(x.min(),x.max())
l,=a.plot(xGrid,cosh2(xGrid,*p),
zorder=10)
labels.append(('fit',parText))
handles.append(l)
a.set_yscale('log')
a.set_xlabel('$x\sigma_0$')
a.set_ylabel('$C(x)/\sigma_0^2$')
a.legend(handles=handles,
labels=labels,
table=True)
pyVis.styling.tightLayout()
\ No newline at end of file
......@@ -314,6 +314,20 @@ class FancyAxes(mpl.axes.Axes):
}
else:
raise Exception()
def legend(self, *args, **kwargs):
handles, labels, extra_args, kwargs = mpl.legend._parse_legend_args(
[self],
*args,
**kwargs)
if len(extra_args):
raise TypeError('legend only accepts two non-keyword arguments')
if kwargs.pop('table',False):
self.legend_ = TableLegend(self,handles,labels,**kwargs)
else:
self.legend_ = Legend(self, handles, labels, **kwargs)
self.legend_._remove_method = self._remove_legend
return self.legend_
......@@ -436,137 +450,139 @@ def heuristicRange(loc,range2,pos):
return retRange
class TextHandlerA(HandlerBase):
def create_artists(self, legend, text ,xdescent, ydescent,
width, height, fontsize, trans):
tx = Text(width/2.,height/2, text, fontsize=fontsize,
ha="center", va="center", fontweight="bold")
return [tx]
from matplotlib import cbook
from matplotlib.offsetbox import HPacker, VPacker, TextArea, DrawingArea
def tableLegend(ax,handles,**kwargs):
class TableLegend(Legend):
'''
This creates a lagend in form of a table:
This class creates a legend in table form, i.e.
colTitle[0] colTitle[1] ...
rowTitle[0] handle[0,0] handle[0,1] ...
rowTitle[1] ... ...
labels[0,1] labels[1,1] ...
labels[0,0] handle[0,0] handle[0,1] ...
labels[1,0] ... ...
...
labels is an iterable of 2-tuples, here, with row title as first item and
column title as second entry.
'''
--------------------------------------------------
def _init_legend_box(self, handles, labels, markerfirst=True):
"""
Initialize the legend_box. The legend_box is an instance of
the OffsetBox, which is packed with legend handles and
texts. Once packed, their location is calculated during the
drawing time.
"""
Parameters:
ax - axes:
Axes to draw the legend on.
handles - iterable of dim n*m or n x m:
Handles corresponding to the table entries. If it is a one-dim.
list/array/..., it should have n*m entries that will be rearranged
into a ractangle as specified by 'order'.
n,m - int:
Dimensions of the table. Only necessary if handles is a one-dim.
list/array/... and neither rowTitles nor colTitles is given (which
should be pretty rare).
oder - str='row'/'col':
This specifies the order if a linear list/array/... is given. The
default is rowwise, i.e.
fontsize = self._fontsize
# legend_box is a HPacker, horizontally packed with
# columns. Each column is a VPacker, vertically packed with
# legend items. Each legend item is HPacker packed with
# legend handleBox and labelBox. handleBox is an instance of
# offsetbox.DrawingArea which contains legend handle. labelBox
# is an instance of offsetbox.TextArea which contains legend
# text.
rowTitles,order=np.unique(np.array(labels)[:,0],return_index=True)
rowTitles=list(rowTitles[order.argsort()])
colTitles,order=np.unique(np.array(labels)[:,1],return_index=True)
colTitles=list(colTitles[order.argsort()])
rowTitles_list=[]
colTitles_list=[]
handle_array=[[None for row in rowTitles] for col in colTitles]
handleBox_array=[[None for row in rowTitles] for col in colTitles]
label_prop = dict(verticalalignment='baseline',
horizontalalignment='left',
fontproperties=self.prop,
)
# The approximate height and descent of text. These values are
# only used for plotting the legend handle.
descent = 0.35 * self._approx_text_height() * (self.handleheight -.3)
# 0.35 and 0.7 are just heuristic numbers and may need to be improved.
height = self._approx_text_height() * self.handleheight - descent
# each handle needs to be drawn inside a box of (x, y, w, h) =
# (0, -descent, width, height). And their coordinates should
# be given in the display coordinates.
# The transformation of each handle will be automatically set
# to self.get_transform(). If the artist does not use its
# default transform (e.g., Collections), you need to
# manually set their transform to the self.get_transform().
legend_handler_map = self.get_legend_handler_map()
for orig_handle, lab in zip(handles, labels):
handler = self.get_legend_handler(legend_handler_map, orig_handle)
if handler is None:
cbook._warn_external(
"Legend does not support {!r} instances.\nA proxy artist "
"may be used instead.\nSee: "
"http://matplotlib.org/users/legend_guide.html"
"#creating-artists-specifically-for-adding-to-the-legend-"
"aka-proxy-artists".format(orig_handle))
else:
handle[0] handle[1] ... handle[m-1]
handle[m] ...
handlebox = DrawingArea(width=self.handlelength * fontsize,
height=height,
xdescent=0., ydescent=descent)
If specified, it might be column wise
index=(rowTitles.index(lab[0]),colTitles.index(lab[1]))
handle[0] handle[n] ...
handle[1] handle[n+1] ...
... ...
# Create the artist for the legend which represents the
# original artist/handle.
handle_array[index[1]][index[0]]=handler.legend_artist(self, orig_handle,
fontsize, handlebox)
handleBox_array[index[1]][index[0]]=handlebox
for col in colTitles:
textbox = TextArea(col, textprops=label_prop,
multilinebaseline=True,
minimumdescent=True)
colTitles_list.append(textbox)
This has no effect on two-dim lists/arrays/...
rowTitles - iter of str:
If given, the titles of the rows. Must have matching length with
the corresponding dim of 'handles'.
for row in rowTitles:
colTitles - iter of str:
If given, the titles of the columns. Must have matching length with
the corresponding dim of 'handles'.
textbox = TextArea(row, textprops=label_prop,
multilinebaseline=True,
minimumdescent=True)
rowTitles_list.append(textbox)
rowPad - int:
Sets the number of white spaces with which the row titles are padded
from the left. Without this (rowPad==0), the row titles are likely
to touch the left boundary of the legend.
Default:2
**kwargs:
All further keyword arguments are passed to the final legend() call.
'''
Legend.update_default_handler_map({str : TextHandlerA()})
if not iterTest(handles):
raise Exception()
rowTitles=kwargs.pop('rowTitles',None)
rowPad=kwargs.pop('rowPad',2)
if not rowTitles is None:
for i in range(len(rowTitles)):
rowTitles[i]=' '*rowPad+rowTitles[i]
colTitles=kwargs.pop('colTitles',None)
order=kwargs.pop('order','row')
if not iterTest(handles[0]):
if not colTitles is None:
n=len(colTitles)
m=int(len(handles)/n)
if not rowTitles is None and m!=len(rowTitles):
raise Exception()
elif not rowTitles is None:
m=len(rowTitles)
n=int(len(handles)/m)
else:
n=kwargs.pop('n',None)
m=kwargs.pop('m',None)
if not n is None:
m=int(len(handles)/n)
elif not m is None:
n=int(len(handles)/m)
if n*m != len(handles):
raise Exception()
if order=='row':
handles=np.array(handles).reshape((n,m))
elif order=='col':
handles=np.array(handles).reshape((m,n)).T
else:
raise Exception()
else:
n,m=np.shape(handles)
hand=np.empty((n+1 if not rowTitles is None else n,m+1 if not colTitles is None else m),dtype=object)
columnbox = [VPacker(pad=0,
sep=self.labelspacing * fontsize,
align='center',
children=[col]+handleBox_array[i]) for i,col in enumerate(colTitles_list)]
if not rowTitles is None:
if not colTitles is None:
rowTitles.insert(0,'')
hand[1:,0]=colTitles
hand[0]=rowTitles
elif not colTitles is None:
hand[:,0]=colTitles
if not rowTitles is None and not colTitles is None:
hand[1:,1:]=handles
elif not rowTitles is None:
hand[1:]=handles
elif not colTitles is None:
hand[:,1:]=handles
ncol=hand.shape[0]
nrow=hand.shape[1]
handletextpad=kwargs.pop('handletextpad',0.)
return ax.legend(hand.reshape(nrow*ncol),['']*nrow*ncol,ncol=ncol,handletextpad=handletextpad,**kwargs)
\ No newline at end of file
if not all([row is None or row=='' for row in rowTitles]):
children=rowTitles_list
if not all([col is None or col=='' for col in colTitles]):
children=[TextArea('', textprops=label_prop,
multilinebaseline=True,
minimumdescent=True)]+children
columnbox=[VPacker(pad=0,
sep=self.labelspacing * fontsize,
align='center',
children=children)]+columnbox
mode = "expand" if self._mode == "expand" else "fixed"
sep = self.columnspacing * fontsize
self._legend_handle_box = HPacker(pad=0,
sep=sep, align="baseline",
mode=mode,
children=columnbox)
self._legend_title_box = TextArea("")
self._legend_box = VPacker(pad=self.borderpad * fontsize,
sep=self.labelspacing * fontsize,
align="center",
children=[self._legend_title_box,
self._legend_handle_box])
self._legend_box.set_figure(self.figure)
self.texts = colTitles_list+rowTitles_list
self.legendHandles=[]
for h in handle_array:
self.legendHandles+=h
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment