@@ -750,6 +750,135 @@ def r(h):
750
750
ax .grid ()
751
751
return ax
752
752
753
+ def _mplplot_plotf (errorbar = False ):
754
+ import matplotlib .pyplot as plt
755
+ def plotf (ax , x , y , style = None , ** kwds ):
756
+ mask = com .isnull (y )
757
+ if mask .any ():
758
+ y = np .ma .array (y )
759
+ y = np .ma .masked_where (mask , y )
760
+
761
+ if errorbar :
762
+ return plt .Axes .errorbar (ax , x , y , ** kwds )
763
+ else :
764
+ # prevent style kwarg from going to errorbar, where it is unsupported
765
+ if style is not None :
766
+ args = (ax , x , y , style )
767
+ else :
768
+ args = (ax , x , y )
769
+ return plt .Axes .plot (* args , ** kwds )
770
+
771
+ return plotf
772
+
773
+
774
+ def _lineplot_plotf (f , stacked , subplots ):
775
+ def plotf (ax , x , y , style = None , column_num = None , ** kwds ):
776
+ # column_num is used to get the target column from protf in line and area plots
777
+ if not hasattr (ax , '_pos_prior' ) or column_num == 0 :
778
+ LinePlot ._initialize_prior (ax , len (y ))
779
+ y_values = LinePlot ._get_stacked_values (ax , y , kwds ['label' ], stacked )
780
+ lines = f (ax , x , y_values , style = style , ** kwds )
781
+ LinePlot ._update_prior (ax , y , stacked , subplots )
782
+ return lines
783
+
784
+ return plotf
785
+
786
+
787
+ def _areaplot_plotf (f , stacked , subplots ):
788
+ import matplotlib .pyplot as plt
789
+ def plotf (ax , x , y , style = None , column_num = None , ** kwds ):
790
+ if not hasattr (ax , '_pos_prior' ) or column_num == 0 :
791
+ LinePlot ._initialize_prior (ax , len (y ))
792
+ y_values = LinePlot ._get_stacked_values (ax , y , kwds ['label' ], stacked )
793
+ lines = f (ax , x , y_values , style = style , ** kwds )
794
+
795
+ # get data from the line to get coordinates for fill_between
796
+ xdata , y_values = lines [0 ].get_data (orig = False )
797
+
798
+ if (y >= 0 ).all ():
799
+ start = ax ._pos_prior
800
+ elif (y <= 0 ).all ():
801
+ start = ax ._neg_prior
802
+ else :
803
+ start = np .zeros (len (y ))
804
+
805
+ if not 'color' in kwds :
806
+ kwds ['color' ] = lines [0 ].get_color ()
807
+
808
+ plt .Axes .fill_between (ax , xdata , start , y_values , ** kwds )
809
+ LinePlot ._update_prior (ax , y , stacked , subplots )
810
+ return lines
811
+
812
+ return plotf
813
+
814
+
815
+ def _histplot_plotf (bins , bottom , stacked , subplots ):
816
+ import matplotlib .pyplot as plt
817
+ def plotf (ax , y , style = None , column_num = None , ** kwds ):
818
+ if not hasattr (ax , '_pos_prior' ) or column_num == 0 :
819
+ LinePlot ._initialize_prior (ax , len (bins ) - 1 )
820
+ y = y [~ com .isnull (y )]
821
+ new_bottom = ax ._pos_prior + bottom
822
+ # ignore style
823
+ n , new_bins , patches = plt .Axes .hist (ax , y , bins = bins ,
824
+ bottom = new_bottom , ** kwds )
825
+ LinePlot ._update_prior (ax , n , stacked , subplots )
826
+ return patches
827
+
828
+ return plotf
829
+
830
+
831
+ def _boxplot_plotf (return_type ):
832
+ def plotf (ax , y , column_num = None , ** kwds ):
833
+ if y .ndim == 2 :
834
+ y = [remove_na (v ) for v in y ]
835
+ # Boxplot fails with empty arrays, so need to add a NaN
836
+ # if any cols are empty
837
+ # GH 8181
838
+ y = [v if v .size > 0 else np .array ([np .nan ]) for v in y ]
839
+ else :
840
+ y = remove_na (y )
841
+ bp = ax .boxplot (y , ** kwds )
842
+
843
+ if return_type == 'dict' :
844
+ return bp , bp
845
+ elif return_type == 'both' :
846
+ return BoxPlot .BP (ax = ax , lines = bp ), bp
847
+ else :
848
+ return ax , bp
849
+
850
+ return plotf
851
+
852
+
853
+ def _kdeplot_plotf (f , bw_method , ind ):
854
+ from scipy .stats import gaussian_kde
855
+ from scipy import __version__ as spv
856
+
857
+ def plotf (ax , y , style = None , column_num = None , ** kwds ):
858
+ y = remove_na (y )
859
+ if LooseVersion (spv ) >= '0.11.0' :
860
+ gkde = gaussian_kde (y , bw_method = bw_method )
861
+ else :
862
+ gkde = gaussian_kde (y )
863
+ if bw_method is not None :
864
+ msg = ('bw_method was added in Scipy 0.11.0.' +
865
+ ' Scipy version in use is %s.' % spv )
866
+ warnings .warn (msg )
867
+
868
+ if ind is None :
869
+ sample_range = max (y ) - min (y )
870
+ ind_local = np .linspace (min (y ) - 0.5 * sample_range ,
871
+ max (y ) + 0.5 * sample_range , 1000 )
872
+ else :
873
+ ind_local = ind
874
+
875
+ y = gkde .evaluate (ind_local )
876
+ lines = f (ax , ind_local , y , style = style , ** kwds )
877
+ return lines
878
+
879
+ return plotf
880
+
881
+
753
882
754
883
class MPLPlot (object ):
755
884
"""
@@ -1182,28 +1311,15 @@ def _is_datetype(self):
1182
1311
index .inferred_type in ('datetime' , 'date' , 'datetime64' ,
1183
1312
'time' ))
1184
1313
1314
+ def _plot_errors (self ):
1315
+ return any (e is not None for e in self .errors .values ())
1316
+
1185
1317
def _get_plot_function (self ):
1186
1318
'''
1187
1319
Returns the matplotlib plotting function (plot or errorbar) based on
1188
1320
the presence of errorbar keywords.
1189
1321
'''
1190
- errorbar = any (e is not None for e in self .errors .values ())
1191
- def plotf (ax , x , y , style = None , ** kwds ):
1192
- mask = com .isnull (y )
1193
- if mask .any ():
1194
- y = np .ma .array (y )
1195
- y = np .ma .masked_where (mask , y )
1196
-
1197
- if errorbar :
1198
- return self .plt .Axes .errorbar (ax , x , y , ** kwds )
1199
- else :
1200
- # prevent style kwarg from going to errorbar, where it is unsupported
1201
- if style is not None :
1202
- args = (ax , x , y , style )
1203
- else :
1204
- args = (ax , x , y )
1205
- return self .plt .Axes .plot (* args , ** kwds )
1206
- return plotf
1322
+ return _mplplot_plotf (self ._plot_errors ())
1207
1323
1208
1324
def _get_index_name (self ):
1209
1325
if isinstance (self .data .index , MultiIndex ):
@@ -1590,7 +1706,6 @@ def _is_ts_plot(self):
1590
1706
return not self .x_compat and self .use_index and self ._use_dynamic_x ()
1591
1707
1592
1708
def _make_plot (self ):
1593
- self ._initialize_prior (len (self .data ))
1594
1709
1595
1710
if self ._is_ts_plot ():
1596
1711
data = self ._maybe_convert_index (self .data )
@@ -1622,12 +1737,13 @@ def _make_plot(self):
1622
1737
left , right = _get_xlim (lines )
1623
1738
ax .set_xlim (left , right )
1624
1739
1625
- def _get_stacked_values (self , y , label ):
1626
- if self .stacked :
1740
+ @classmethod
1741
+ def _get_stacked_values (cls , ax , y , label , stacked ):
1742
+ if stacked :
1627
1743
if (y >= 0 ).all ():
1628
- return self ._pos_prior + y
1744
+ return ax ._pos_prior + y
1629
1745
elif (y <= 0 ).all ():
1630
- return self ._neg_prior + y
1746
+ return ax ._neg_prior + y
1631
1747
else :
1632
1748
raise ValueError ('When stacked is True, each column must be either all positive or negative.'
1633
1749
'{0} contains both positive and negative values' .format (label ))
@@ -1636,15 +1752,8 @@ def _get_stacked_values(self, y, label):
1636
1752
1637
1753
def _get_plot_function (self ):
1638
1754
f = MPLPlot ._get_plot_function (self )
1639
- def plotf (ax , x , y , style = None , column_num = None , ** kwds ):
1640
- # column_num is used to get the target column from protf in line and area plots
1641
- if column_num == 0 :
1642
- self ._initialize_prior (len (self .data ))
1643
- y_values = self ._get_stacked_values (y , kwds ['label' ])
1644
- lines = f (ax , x , y_values , style = style , ** kwds )
1645
- self ._update_prior (y )
1646
- return lines
1647
- return plotf
1755
+
1756
+ return _lineplot_plotf (f , self .stacked , self .subplots )
1648
1757
1649
1758
def _get_ts_plot_function (self ):
1650
1759
from pandas .tseries .plotting import tsplot
@@ -1656,19 +1765,21 @@ def _plot(ax, x, data, style=None, **kwds):
1656
1765
return lines
1657
1766
return _plot
1658
1767
1659
- def _initialize_prior (self , n ):
1660
- self ._pos_prior = np .zeros (n )
1661
- self ._neg_prior = np .zeros (n )
1768
+ @classmethod
1769
+ def _initialize_prior (cls , ax , n ):
1770
+ ax ._pos_prior = np .zeros (n )
1771
+ ax ._neg_prior = np .zeros (n )
1662
1772
1663
- def _update_prior (self , y ):
1664
- if self .stacked and not self .subplots :
1773
+ @classmethod
1774
+ def _update_prior (cls , ax , y , stacked , subplots ):
1775
+ if stacked and not subplots :
1665
1776
# tsplot resample may changedata length
1666
- if len (self ._pos_prior ) != len (y ):
1667
- self ._initialize_prior (len (y ))
1777
+ if len (ax ._pos_prior ) != len (y ):
1778
+ cls ._initialize_prior (ax , len (y ))
1668
1779
if (y >= 0 ).all ():
1669
- self ._pos_prior += y
1780
+ ax ._pos_prior += y
1670
1781
elif (y <= 0 ).all ():
1671
- self ._neg_prior += y
1782
+ ax ._neg_prior += y
1672
1783
1673
1784
def _maybe_convert_index (self , data ):
1674
1785
# tsplot converts automatically, but don't want to convert index
@@ -1735,28 +1846,8 @@ def _get_plot_function(self):
1735
1846
raise ValueError ("Log-y scales are not supported in area plot" )
1736
1847
else :
1737
1848
f = MPLPlot ._get_plot_function (self )
1738
- def plotf (ax , x , y , style = None , column_num = None , ** kwds ):
1739
- if column_num == 0 :
1740
- self ._initialize_prior (len (self .data ))
1741
- y_values = self ._get_stacked_values (y , kwds ['label' ])
1742
- lines = f (ax , x , y_values , style = style , ** kwds )
1743
-
1744
- # get data from the line to get coordinates for fill_between
1745
- xdata , y_values = lines [0 ].get_data (orig = False )
1746
-
1747
- if (y >= 0 ).all ():
1748
- start = self ._pos_prior
1749
- elif (y <= 0 ).all ():
1750
- start = self ._neg_prior
1751
- else :
1752
- start = np .zeros (len (y ))
1753
-
1754
- if not 'color' in kwds :
1755
- kwds ['color' ] = lines [0 ].get_color ()
1756
1849
1757
- self .plt .Axes .fill_between (ax , xdata , start , y_values , ** kwds )
1758
- self ._update_prior (y )
1759
- return lines
1850
+ return _areaplot_plotf (f , self .stacked , self .subplots )
1760
1851
1761
1852
return plotf
1762
1853
@@ -1946,17 +2037,7 @@ def _args_adjust(self):
1946
2037
self .bottom = np .array (self .bottom )
1947
2038
1948
2039
def _get_plot_function (self ):
1949
- def plotf (ax , y , style = None , column_num = None , ** kwds ):
1950
- if column_num == 0 :
1951
- self ._initialize_prior (len (self .bins ) - 1 )
1952
- y = y [~ com .isnull (y )]
1953
- bottom = self ._pos_prior + self .bottom
1954
- # ignore style
1955
- n , bins , patches = self .plt .Axes .hist (ax , y , bins = self .bins ,
1956
- bottom = bottom , ** kwds )
1957
- self ._update_prior (n )
1958
- return patches
1959
- return plotf
2040
+ return _histplot_plotf (self .bins , self .bottom , self .stacked , self .subplots )
1960
2041
1961
2042
def _make_plot (self ):
1962
2043
plotf = self ._get_plot_function ()
@@ -2003,35 +2084,9 @@ def __init__(self, data, bw_method=None, ind=None, **kwargs):
2003
2084
def _args_adjust (self ):
2004
2085
pass
2005
2086
2006
- def _get_ind (self , y ):
2007
- if self .ind is None :
2008
- sample_range = max (y ) - min (y )
2009
- ind = np .linspace (min (y ) - 0.5 * sample_range ,
2010
- max (y ) + 0.5 * sample_range , 1000 )
2011
- else :
2012
- ind = self .ind
2013
- return ind
2014
-
2015
2087
def _get_plot_function (self ):
2016
- from scipy .stats import gaussian_kde
2017
- from scipy import __version__ as spv
2018
2088
f = MPLPlot ._get_plot_function (self )
2019
- def plotf (ax , y , style = None , column_num = None , ** kwds ):
2020
- y = remove_na (y )
2021
- if LooseVersion (spv ) >= '0.11.0' :
2022
- gkde = gaussian_kde (y , bw_method = self .bw_method )
2023
- else :
2024
- gkde = gaussian_kde (y )
2025
- if self .bw_method is not None :
2026
- msg = ('bw_method was added in Scipy 0.11.0.' +
2027
- ' Scipy version in use is %s.' % spv )
2028
- warnings .warn (msg )
2029
-
2030
- ind = self ._get_ind (y )
2031
- y = gkde .evaluate (ind )
2032
- lines = f (ax , ind , y , style = style , ** kwds )
2033
- return lines
2034
- return plotf
2089
+ return _kdeplot_plotf (f , self .bw_method , self .ind )
2035
2090
2036
2091
def _post_plot_logic (self ):
2037
2092
for ax in self .axes :
@@ -2126,24 +2181,7 @@ def _args_adjust(self):
2126
2181
self .sharey = False
2127
2182
2128
2183
def _get_plot_function (self ):
2129
- def plotf (ax , y , column_num = None , ** kwds ):
2130
- if y .ndim == 2 :
2131
- y = [remove_na (v ) for v in y ]
2132
- # Boxplot fails with empty arrays, so need to add a NaN
2133
- # if any cols are empty
2134
- # GH 8181
2135
- y = [v if v .size > 0 else np .array ([np .nan ]) for v in y ]
2136
- else :
2137
- y = remove_na (y )
2138
- bp = ax .boxplot (y , ** kwds )
2139
-
2140
- if self .return_type == 'dict' :
2141
- return bp , bp
2142
- elif self .return_type == 'both' :
2143
- return self .BP (ax = ax , lines = bp ), bp
2144
- else :
2145
- return ax , bp
2146
- return plotf
2184
+ return _boxplot_plotf (self .return_type )
2147
2185
2148
2186
def _validate_color_args (self ):
2149
2187
if 'color' in self .kwds :
0 commit comments