Skip to content

Commit 31ee064

Browse files
committed
BUG: support dateutil 2.1, fix scatter_matrix axis labels. #1637 #1625
1 parent e1129b1 commit 31ee064

File tree

5 files changed

+86
-58
lines changed

5 files changed

+86
-58
lines changed

RELEASE.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ pandas 0.8.1
8585
- Better handle errors with non-existing objects in HDFStore (#1254)
8686
- Don't copy int64 array data in DatetimeIndex when copy=False (#1624)
8787
- Fix resampling of conforming periods quarterly to annual (#1622)
88+
- Don't lose index name on resampling (#1631)
89+
- Support python-dateutil version 2.1 (#1637)
90+
- Fix broken scatter_matrix axis labeling, esp. with time series (#1625)
8891

8992
pandas 0.8.0
9093
============

TODO.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,7 @@ Performance blog
5757
- Take
5858

5959
git log v0.6.1..master --pretty=format:%aN | sort | uniq -c | sort -rn
60-
git log a8c2f88..master --pretty=format:%aN | sort | uniq -c | sort -rn
60+
61+
git log 7ddfbd4..master --pretty=format:%aN | sort | uniq -c | sort -rn
62+
git log a0257f5..master --pretty=format:%aN | sort | uniq -c | sort -rn
63+

pandas/tools/plotting.py

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ def scatter_matrix(frame, alpha=0.5, figsize=None, ax=None, grid=False,
4646
>>> df = DataFrame(np.random.randn(1000, 4), columns=['A','B','C','D'])
4747
>>> scatter_matrix(df, alpha=0.2)
4848
"""
49+
from matplotlib.artist import setp
50+
4951
df = frame._get_numeric_data()
5052
n = df.columns.size
5153
fig, axes = _subplots(nrows=n, ncols=n, figsize=figsize, ax=ax,
@@ -60,76 +62,74 @@ def scatter_matrix(frame, alpha=0.5, figsize=None, ax=None, grid=False,
6062

6163
for i, a in zip(range(n), df.columns):
6264
for j, b in zip(range(n), df.columns):
65+
ax = axes[i, j]
66+
6367
if i == j:
6468
values = df[a].values[mask[a].values]
6569

6670
# Deal with the diagonal by drawing a histogram there.
6771
if diagonal == 'hist':
68-
axes[i, j].hist(values)
72+
ax.hist(values)
6973
elif diagonal in ('kde', 'density'):
7074
from scipy.stats import gaussian_kde
7175
y = values
7276
gkde = gaussian_kde(y)
7377
ind = np.linspace(y.min(), y.max(), 1000)
74-
axes[i, j].plot(ind, gkde.evaluate(ind), **kwds)
78+
ax.plot(ind, gkde.evaluate(ind), **kwds)
7579
else:
7680
common = (mask[a] & mask[b]).values
7781

78-
axes[i, j].scatter(df[b][common], df[a][common],
82+
ax.scatter(df[b][common], df[a][common],
7983
marker=marker, alpha=alpha, **kwds)
8084

81-
axes[i, j].set_xlabel('')
82-
axes[i, j].set_ylabel('')
83-
axes[i, j].set_xticklabels([])
84-
axes[i, j].set_yticklabels([])
85-
ticks = df.index
86-
87-
is_datetype = ticks.inferred_type in ('datetime', 'date',
88-
'datetime64')
85+
ax.set_xlabel('')
86+
ax.set_ylabel('')
8987

90-
if ticks.is_numeric() or is_datetype:
91-
"""
92-
Matplotlib supports numeric values or datetime objects as
93-
xaxis values. Taking LBYL approach here, by the time
94-
matplotlib raises exception when using non numeric/datetime
95-
values for xaxis, several actions are already taken by plt.
96-
"""
97-
ticks = ticks._mpl_repr()
88+
ax.xaxis.set_visible(False)
89+
ax.yaxis.set_visible(False)
9890

9991
# setup labels
10092
if i == 0 and j % 2 == 1:
101-
axes[i, j].set_xlabel(b, visible=True)
102-
#axes[i, j].xaxis.set_visible(True)
103-
axes[i, j].set_xlabel(b)
104-
axes[i, j].set_xticklabels(ticks)
105-
axes[i, j].xaxis.set_ticks_position('top')
106-
axes[i, j].xaxis.set_label_position('top')
107-
if i == n - 1 and j % 2 == 0:
108-
axes[i, j].set_xlabel(b, visible=True)
109-
#axes[i, j].xaxis.set_visible(True)
110-
axes[i, j].set_xlabel(b)
111-
axes[i, j].set_xticklabels(ticks)
112-
axes[i, j].xaxis.set_ticks_position('bottom')
113-
axes[i, j].xaxis.set_label_position('bottom')
114-
if j == 0 and i % 2 == 0:
115-
axes[i, j].set_ylabel(a, visible=True)
116-
#axes[i, j].yaxis.set_visible(True)
117-
axes[i, j].set_ylabel(a)
118-
axes[i, j].set_yticklabels(ticks)
119-
axes[i, j].yaxis.set_ticks_position('left')
120-
axes[i, j].yaxis.set_label_position('left')
121-
if j == n - 1 and i % 2 == 1:
122-
axes[i, j].set_ylabel(a, visible=True)
123-
#axes[i, j].yaxis.set_visible(True)
124-
axes[i, j].set_ylabel(a)
125-
axes[i, j].set_yticklabels(ticks)
126-
axes[i, j].yaxis.set_ticks_position('right')
127-
axes[i, j].yaxis.set_label_position('right')
128-
129-
axes[i, j].grid(b=grid)
93+
ax.set_xlabel(b, visible=True)
94+
ax.xaxis.set_visible(True)
95+
ax.set_xlabel(b)
96+
ax.xaxis.set_ticks_position('top')
97+
ax.xaxis.set_label_position('top')
98+
setp(ax.get_xticklabels(), rotation=90)
99+
elif i == n - 1 and j % 2 == 0:
100+
ax.set_xlabel(b, visible=True)
101+
ax.xaxis.set_visible(True)
102+
ax.set_xlabel(b)
103+
ax.xaxis.set_ticks_position('bottom')
104+
ax.xaxis.set_label_position('bottom')
105+
setp(ax.get_xticklabels(), rotation=90)
106+
elif j == 0 and i % 2 == 0:
107+
ax.set_ylabel(a, visible=True)
108+
ax.yaxis.set_visible(True)
109+
ax.set_ylabel(a)
110+
ax.yaxis.set_ticks_position('left')
111+
ax.yaxis.set_label_position('left')
112+
elif j == n - 1 and i % 2 == 1:
113+
ax.set_ylabel(a, visible=True)
114+
ax.yaxis.set_visible(True)
115+
ax.set_ylabel(a)
116+
ax.yaxis.set_ticks_position('right')
117+
ax.yaxis.set_label_position('right')
118+
119+
# ax.grid(b=grid)
120+
121+
axes[0, 0].yaxis.set_visible(False)
122+
axes[n-1, n-1].xaxis.set_visible(False)
123+
axes[n-1, n-1].yaxis.set_visible(False)
124+
axes[0, n - 1].yaxis.tick_right()
125+
126+
for ax in axes.flat:
127+
setp(ax.get_xticklabels(), fontsize=8)
128+
setp(ax.get_yticklabels(), fontsize=8)
130129

131130
return axes
132131

132+
133133
def _gca():
134134
import matplotlib.pyplot as plt
135135
return plt.gca()

pandas/tseries/tests/test_plotting.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ def test_finder_quarterly(self):
334334
@slow
335335
def test_finder_monthly(self):
336336
import matplotlib.pyplot as plt
337-
xp = Period('1988-1').ordinal
337+
xp = Period('Jan 1988').ordinal
338338
yrs = [1.15, 2.5, 4, 11]
339339
plt.close('all')
340340
for n in yrs:

pandas/tseries/tools.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99

1010
try:
1111
import dateutil
12-
from dateutil.parser import parser
12+
from dateutil.parser import parse
1313
from dateutil.relativedelta import relativedelta
1414

1515
# raise exception if dateutil 2.0 install on 2.x platform
1616
if (sys.version_info[0] == 2 and
17-
dateutil.__version__ >= '2.0'): # pragma: no cover
17+
dateutil.__version__ == '2.0'): # pragma: no cover
1818
raise Exception('dateutil 2.0 incompatible with Python 2.x, you must '
19-
'install version 1.5!')
19+
'install version 1.5 or 2.1+!')
2020
except ImportError: # pragma: no cover
2121
print 'Please install python-dateutil via easy_install or some method!'
2222
raise # otherwise a 2nd import won't show the message
@@ -98,7 +98,7 @@ def to_datetime(arg, errors='ignore', dayfirst=False, box=True):
9898
try:
9999
if not arg:
100100
return arg
101-
return _dtparser.parse(arg, dayfirst=dayfirst)
101+
return parse(arg, dayfirst=dayfirst)
102102
except Exception:
103103
if errors == 'raise':
104104
raise
@@ -109,15 +109,13 @@ class DateParseError(ValueError):
109109
pass
110110

111111

112-
_dtparser = parser()
113-
114112

115113
# patterns for quarters like '4Q2005', '05Q1'
116114
qpat1full = re.compile(r'(\d)Q(\d\d\d\d)')
117115
qpat2full = re.compile(r'(\d\d\d\d)Q(\d)')
118116
qpat1 = re.compile(r'(\d)Q(\d\d)')
119117
qpat2 = re.compile(r'(\d\d)Q(\d)')
120-
118+
ypat = re.compile(r'(\d\d\d\d)$')
121119

122120
def parse_time_string(arg, freq=None):
123121
"""
@@ -149,6 +147,11 @@ def parse_time_string(arg, freq=None):
149147

150148
# special handling for possibilities eg, 2Q2005, 2Q05, 2005Q1, 05Q1
151149
if len(arg) in [4, 6]:
150+
m = ypat.match(arg)
151+
if m:
152+
ret = default.replace(year=int(m.group(1)))
153+
return ret, ret, 'year'
154+
152155
add_century = False
153156
if len(arg) == 4:
154157
add_century = True
@@ -192,11 +195,30 @@ def parse_time_string(arg, freq=None):
192195
except Exception:
193196
pass
194197

198+
# f7u12
199+
try:
200+
ret = datetime.strptime(arg, '%Y-%m')
201+
return ret, ret, 'month'
202+
except Exception:
203+
pass
204+
205+
try:
206+
ret = datetime.strptime(arg, '%b %Y')
207+
return ret, ret, 'month'
208+
except Exception:
209+
pass
210+
211+
try:
212+
ret = datetime.strptime(arg, '%b-%Y')
213+
return ret, ret, 'month'
214+
except Exception:
215+
pass
216+
195217
dayfirst = print_config.date_dayfirst
196218
yearfirst = print_config.date_yearfirst
197219

198220
try:
199-
parsed = _dtparser._parse(arg, dayfirst=dayfirst, yearfirst=yearfirst)
221+
parsed = parse(arg, dayfirst=dayfirst, yearfirst=yearfirst)
200222
except Exception, e:
201223
raise DateParseError(e)
202224

0 commit comments

Comments
 (0)