Skip to content

Commit

Permalink
Update Test Suite
Browse files Browse the repository at this point in the history
  • Loading branch information
morganjwilliams committed Jul 11, 2018
1 parent bd4229e commit f32e17c
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 23 deletions.
10 changes: 4 additions & 6 deletions pyrolite/util/pandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,11 @@ def to_numeric(df: pd.DataFrame,
errors: str = 'coerce'):
"""
Takes all non-metadata columns and converts to numeric type where possible.
Could be reimplemented to operate per-column for better memory performance.
"""
num_headers = tuple([i for i in df.columns if i not in exclude])
df.loc[:, num_headers] = df.loc[:, num_headers].apply(pd.to_numeric,
axis=0,
errors=errors)
num_headers = [i for i in df.columns if i not in exclude]
df[num_headers] = df.loc[:, num_headers].apply(pd.to_numeric,
axis=1, # across cols
errors=errors)
return df


Expand Down
10 changes: 8 additions & 2 deletions pyrolite/util/spatial.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import numpy as np

import itertools

def piecewise(segment_ranges:list, segments=2, output_fmt=np.float):
"""
Expand All @@ -11,7 +11,7 @@ def piecewise(segment_ranges:list, segments=2, output_fmt=np.float):
segments = list(np.ones(len(segment_ranges)) * segments)
else:
pass
seg_width = [(max([x1, x2]) - min([x1, x2])) / segments[ix]
seg_width = [(x2 - x1) / segments[ix] # can have negative steps
for ix, (x1, x2) in enumerate(segment_ranges)]
separators = [np.linspace(x1, x2, segments[ix]+1)[:-1]
for ix, (x1, x2) in enumerate(segment_ranges)]
Expand All @@ -25,6 +25,8 @@ def piecewise(segment_ranges:list, segments=2, output_fmt=np.float):

def spatiotemporal_split(segments=4,
nan_lims=[np.nan, np.nan],
#usebounds=False,
#order=['minx', 'miny', 'maxx', 'maxy'],
**kwargs):
"""
Creates spatiotemporal grid using piecewise function and arbitrary
Expand All @@ -51,6 +53,10 @@ def spatiotemporal_split(segments=4,

items = {k: v for (k, v) in items.items()
if not np.isnan(v)}
#if usebounds:
# bounds = NSEW_2_bounds(items, order=order)
# yield bounds
#else:
yield items


Expand Down
22 changes: 21 additions & 1 deletion test/test_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from numpy.random import multivariate_normal
import ternary
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.axes as matax

from pyrolite.geochem import REE, common_elements
Expand Down Expand Up @@ -59,6 +60,7 @@ def test_noplot_nofill(self):
"""Test failure on no-plot no-fill options."""
out = spiderplot(self.df, plot=False, fill=False)
self.assertTrue(isinstance(out, Maxes.Axes))
plt.close('all')

def test_valid_style(self):
"""Test valid styling options."""
Expand All @@ -70,11 +72,17 @@ def test_irrellevant_style_options(self):
with self.assertWarns(UserWarning):
ax = spiderplot(self.df, **style)

plt.close('all')

@unittest.expectedFailure
def test_invalid_style_options(self):
"""Test stability under invalid style values."""
style = {'color': 'notacolor', 'marker': 'red'}
spiderplot(self.df, **style)
plt.close('all')

def tearDown(self):
plt.close('all')

class TestTernaryplot(unittest.TestCase):
"""Tests the Ternaryplot functionality."""
Expand All @@ -90,26 +98,31 @@ def test_none(self):
out = ternaryplot(df)
self.assertEqual(type(out),
ternary.ternary_axes_subplot.TernaryAxesSubplot)

plt.close('all')

def test_one(self):
"""Test generation of plot with one record."""
df = self.df.head(1)
out = ternaryplot(df)
self.assertEqual(type(out),
ternary.ternary_axes_subplot.TernaryAxesSubplot)
plt.close('all')

def test_multiple(self):
"""Test generation of plot with multiple records."""
df = self.df.loc[:, :]
out = ternaryplot(df)
self.assertEqual(type(out),
ternary.ternary_axes_subplot.TernaryAxesSubplot)
plt.close('all')

def test_overplotting(self):
"""Test use of the plot for multiple rounds of plotting."""
pass

def tearDown(self):
plt.close('all')


class TestDensityplot(unittest.TestCase):
"""Tests the Densityplot functionality."""
Expand All @@ -133,6 +146,7 @@ def test_none(self):
with self.subTest(df=df):
out = densityplot(df)
self.assertTrue(isinstance(out, matax.Axes))
plt.close('all')


def test_one(self):
Expand All @@ -142,13 +156,15 @@ def test_one(self):
with self.subTest(df=df):
out = densityplot(self.bidf)
self.assertTrue(isinstance(out, matax.Axes))
plt.close('all')

def test_multiple(self):
"""Test generation of plot with multiple records."""
for df in [self.bidf, self.tridf]:
with self.subTest(df=df):
out = densityplot(df)
self.assertTrue(isinstance(out, matax.Axes))
plt.close('all')


def test_modes(self):
Expand All @@ -159,6 +175,7 @@ def test_modes(self):
with self.subTest(mode=mode):
out = densityplot(df, mode=mode)
self.assertTrue(isinstance(out, matax.Axes))
plt.close('all')

def test_bivariate_logscale(self):
"""Tests logscale for different ploting modes using bivariate data."""
Expand All @@ -169,12 +186,15 @@ def test_bivariate_logscale(self):
with self.subTest(mode=mode):
out = densityplot(df, mode=mode)
self.assertTrue(isinstance(out, matax.Axes))
plt.close('all')


def test_overplotting(self):
"""Test use of the plot for multiple rounds of plotting."""
pass

def tearDown(self):
plt.close('all')

if __name__ == '__main__':
unittest.main()
70 changes: 56 additions & 14 deletions test/util/test_util_pandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
from pyrolite.util.pandas import *
from pathlib import Path

def test_df(cols=['SiO2', 'CaO', 'MgO', 'FeO', 'TiO2'],
index_length=10):
return pd.DataFrame({k: v for k,v in zip(cols,
np.random.rand(len(cols), index_length))})

def test_ser(index=['SiO2', 'CaO', 'MgO', 'FeO', 'TiO2']):
return pd.Series({k: v for k,v in zip(index, np.random.rand(len(index)))})


class TestColumnOrderedAppend(unittest.TestCase):

Expand All @@ -21,44 +29,78 @@ def test_index_preservation(self):
class TestAccumulate(unittest.TestCase):

def setUp(self):
pass
self.df0 = test_df()
self.others = [test_df()]*4

def test_column_order(self):
pass
result = accumulate([self.df0]+self.others)
self.assertTrue(all(result.columns == self.df0.columns))

def test_index_preservation(self):
pass
result = accumulate([self.df0]+self.others)
# The range index should just be repeated 5 times, not reset
self.assertTrue(all([res==exp for (res, exp) in
zip(list(result.index.values),
list(np.tile(self.df0.index.values, 5)))]
))


class TestToFrame(unittest.TestCase):

def setUp(self):
self.ser = pd.Series()
self.df = pd.Series()
self.ser = test_ser()
self.df = test_df()

def test_column_order(self):
pass
def test_df_column_order(self):
result = to_frame(self.df)
self.assertTrue(all(result.columns == self.df.columns))

def test_index_preservation(self):
pass
def test_ser_column_order(self):
result = to_frame(self.ser)
self.assertTrue(all(result.columns == self.ser.index))

def test_df_index_preservation(self):
result = to_frame(self.df)
self.assertTrue(all(result.index == self.df.index))

def test_series_conversion(self):
result = to_frame(self.ser)
self.assertTrue(isinstance(result, pd.DataFrame))




class TestToNumeric(unittest.TestCase):

def setUp(self):
pass
self.df = test_df().applymap(str)

def test_numeric(self):
df = self.df
result = to_numeric(df)
self.assertTrue((result.dtypes == 'float64').all())

def test_exclude(self):
pass
df = self.df
exclude = ['TiO2']
num_columns = [c for c in df.columns if c not in exclude]
result = to_numeric(df, exclude=exclude)

self.assertTrue((result.loc[:, exclude].dtypes != 'float64').all())
self.assertTrue((result.loc[:, num_columns].dtypes == 'float64').all())

def test_error_methods(self):
pass
df = self.df
df.loc[0, 'SiO2'] = 'Low'
for method in ['ignore', 'raise', 'coerce']:
with self.subTest(method=method):
try:
result = to_numeric(df, errors=method)
self.assertTrue(method in ['ignore', 'coerce'])
if method == 'ignore':
self.assertTrue(result.loc[0, 'SiO2'] == 'Low')
else:
self.assertTrue(pd.isnull(result.loc[0, 'SiO2']))
except:
self.assertTrue(method=='raise')


class TestConcatColumns(unittest.TestCase):
Expand Down
90 changes: 90 additions & 0 deletions test/util/test_util_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import unittest
import pandas as pd
import numpy as np
import matplotlib.axes as matax
import matplotlib.pyplot as plt
from pyrolite.util.plot import *
from sklearn.decomposition import PCA
from pyrolite.compositions import close


# add_colorbar

# ABC_to_tern_xy

# tern_heatmapcoords

# proxy_rect

# proxy_line

# draw_vector

# vector_to_line

class TestDrawVector(unittest.TestCase):

def setUp(self):
xs = 1./(np.random.randn(5)+4)
self.X = np.array([xs, 1-xs])
self.X = close(self.X)

def test_plot(self):
fig, ax = plt.subplots(1)
pca = PCA(n_components=2)
d = self.X
pca.fit(d)
for variance, vector in zip(pca.explained_variance_, pca.components_):
v = vector[:2] * 3 * np.sqrt(variance)
draw_vector(pca.mean_[:2], pca.mean_[:2] + v, ax=ax)

def tearDown(self):
plt.close('all')


class TestVectorToLine(unittest.TestCase):

def setUp(self):
xs = 1./(np.random.randn(5)+4)
self.X = np.array([xs, 1-xs])
self.X = close(self.X)

def test_to_line(self):
pca = PCA(n_components=2)
d = self.X
pca.fit(d)
for variance, vector in zip(pca.explained_variance_, pca.components_):
line = vector_to_line(pca.mean_[:2], vector[:2], variance, spans=6)

self.assertTrue(isinstance(line, np.ndarray))
self.assertTrue(line.shape[1] == 2)

# plot_2dhull


class TestNaNScatter(unittest.TestCase):

def setUp(self):
self.x = np.random.randn(1000) - 1
self.y = 2 + np.random.randn(1000)
self.x[self.x < -1] = np.nan
self.y[self.y < 2] = np.nan

def test_plot(self):
fig, ax = plt.subplots()
ax = nan_scatter(ax, self.x, self.y)
self.assertTrue(isinstance(ax, matax.Axes))

def tearDown(self):
plt.close('all')


# save_figure

# save_axes

# get_full_extent


if __name__ == '__main__':
unittest.main()

0 comments on commit f32e17c

Please sign in to comment.