Hello community, here is the log from the commit of package python-mizani for openSUSE:Factory checked in at 2020-07-10 15:30:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-mizani (Old) and /work/SRC/openSUSE:Factory/.python-mizani.new.3060 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-mizani" Fri Jul 10 15:30:59 2020 rev:2 rq:819927 version:0.7.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-mizani/python-mizani.changes 2019-12-04 14:20:36.714449861 +0100 +++ /work/SRC/openSUSE:Factory/.python-mizani.new.3060/python-mizani.changes 2020-07-10 15:31:01.210850437 +0200 @@ -1,0 +2,11 @@ +Fri Jul 10 09:01:26 UTC 2020 - Marketa Calabkova <[email protected]> + +- Update to version 0.7.1 + * Fixed issue with :class:`mizani.formatters.log_breaks` where non-linear + breaks could not be generated if the limits where greater than the largest + integer sys.maxsize. + * Fixed :func:`mizani.palettes.gradient_n_pal` to return nan for nan values. + * Fixed :func:`mizani.scales.scale_discrete.train` when training categoricals + to maintain the order. + +------------------------------------------------------------------- Old: ---- mizani-0.6.0.tar.gz New: ---- mizani-0.7.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-mizani.spec ++++++ --- /var/tmp/diff_new_pack.ABTqkT/_old 2020-07-10 15:31:02.038853161 +0200 +++ /var/tmp/diff_new_pack.ABTqkT/_new 2020-07-10 15:31:02.042853174 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-mizani # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-mizani -Version: 0.6.0 +Version: 0.7.1 Release: 0 Summary: Scales for Python License: BSD-3-Clause @@ -49,6 +49,8 @@ %prep %setup -q -n mizani-%{version} +# correct np.timedelta64 usage +sed -i 's/unit=//' mizani/tests/test_*.py %build %python_build ++++++ mizani-0.6.0.tar.gz -> mizani-0.7.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/PKG-INFO new/mizani-0.7.1/PKG-INFO --- old/mizani-0.6.0/PKG-INFO 2019-08-15 14:38:39.000000000 +0200 +++ new/mizani-0.7.1/PKG-INFO 2020-06-05 00:46:54.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: mizani -Version: 0.6.0 +Version: 0.7.1 Summary: Scales for Python Home-page: https://github.com/has2k1/mizani Maintainer: Hassan Kibirige diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/_version.py new/mizani-0.7.1/mizani/_version.py --- old/mizani-0.6.0/mizani/_version.py 2019-08-15 14:38:39.000000000 +0200 +++ new/mizani-0.7.1/mizani/_version.py 2020-06-05 00:46:54.000000000 +0200 @@ -8,11 +8,11 @@ version_json = ''' { - "date": "2019-08-15T15:19:49+0300", + "date": "2020-06-04T23:24:33+0300", "dirty": false, "error": null, - "full-revisionid": "c67e3665f71b7961c97fc24e2940ec47e3724693", - "version": "0.6.0" + "full-revisionid": "e1eb9b2bd362f0462156a3b114585d1c037072ca", + "version": "0.7.1" } ''' # END VERSION_JSON diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/bounds.py new/mizani-0.7.1/mizani/bounds.py --- old/mizani-0.6.0/mizani/bounds.py 2019-06-05 12:50:34.000000000 +0200 +++ new/mizani-0.7.1/mizani/bounds.py 2020-06-03 21:48:57.000000000 +0200 @@ -349,7 +349,9 @@ finite = np.repeat(True, len(x)) if hasattr(x, 'dtype'): - outside = (x < range[0]) | (x > range[1]) + # Ignore RuntimeWarning when x contains nans + with np.errstate(invalid='ignore'): + outside = (x < range[0]) | (x > range[1]) bool_idx = finite & outside x = x.copy() x[bool_idx] = null diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/breaks.py new/mizani-0.7.1/mizani/breaks.py --- old/mizani-0.6.0/mizani/breaks.py 2019-07-10 13:51:46.000000000 +0200 +++ new/mizani-0.7.1/mizani/breaks.py 2020-06-04 01:20:45.000000000 +0200 @@ -10,6 +10,8 @@ breaks make interpretation straight forward. These functions provide ways to calculate good(hopefully) breaks. """ +import sys + import numpy as np import pandas as pd from matplotlib.dates import MinuteLocator, HourLocator, DayLocator @@ -141,6 +143,10 @@ _min = int(np.floor(rng[0])) _max = int(np.ceil(rng[1])) + # Prevent overflow + if float(base) ** _max > sys.maxsize: + base = float(base) + # numpy arrays with -ve number(s) and of dtype=int # cannot be powers i.e. base ** arr fails dtype = float if _min < 0 or _max < 0 else int @@ -198,6 +204,10 @@ dtype = float if _min < 0 or _max < 0 else int steps = [1] + # Prevent overflow + if float(base) ** _max > sys.maxsize: + base = float(base) + def delta(x): """ Calculates the smallest distance in the log scale between the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/formatters.py new/mizani-0.7.1/mizani/formatters.py --- old/mizani-0.6.0/mizani/formatters.py 2019-08-15 14:14:43.000000000 +0200 +++ new/mizani-0.7.1/mizani/formatters.py 2020-06-04 13:23:00.000000000 +0200 @@ -369,12 +369,6 @@ self.base = base self.exponent_limits = exponent_limits - if 'exponent_threshold' in kwargs: - warn( - "`exponent_threshold` parameter has been deprecated ", - "Use exponent_limits instead", - DeprecationWarning) - def _tidyup_labels(self, labels): """ Make all labels uniform in format and remove redundant zeros diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/palettes.py new/mizani-0.7.1/mizani/palettes.py --- old/mizani-0.6.0/mizani/palettes.py 2019-08-15 14:14:43.000000000 +0200 +++ new/mizani-0.7.1/mizani/palettes.py 2020-06-04 13:23:00.000000000 +0200 @@ -17,6 +17,7 @@ import colorsys import numpy as np +import pandas as pd import matplotlib as mpl import matplotlib.colors as mcolors from matplotlib.cm import get_cmap @@ -254,14 +255,12 @@ grey_cmap = mcolors.LinearSegmentedColormap('grey', cdict) def continuous_grey_palette(n): - colors = [] # The grey scale points are linearly separated in # gamma encoded space - for x in np.linspace(start**gamma, end**gamma, n): - # Map points onto the [0, 1] palette domain - x = (x ** (1./gamma) - start) / (end - start) - colors.append(mcolors.rgb2hex(grey_cmap(x))) - return colors + x = np.linspace(start**gamma, end**gamma, n) + # Map points onto the [0, 1] palette domain + vals = (x ** (1./gamma) - start) / (end - start) + return ratios_to_colors(vals, grey_cmap) return continuous_grey_palette @@ -368,76 +367,35 @@ if direction != 1 and direction != -1: raise ValueError("direction should be 1 or -1.") - def full_type_name(text): - abbrevs = { - 'seq': 'Sequential', - 'qual': 'Qualitative', - 'div': 'Diverging' - } - text = abbrevs.get(text, text) - return text.title() - - def number_to_palette_name(ctype, n): - """ - Return palette name that corresponds to a given number - - Uses alphabetical ordering - """ - n -= 1 - palettes = sorted(colorbrewer.COLOR_MAPS[ctype].keys()) - if n < len(palettes): - return palettes[n] - - raise ValueError( - "There are only '{}' palettes of type {}. " - "You requested palette no. {}".format(len(palettes), - ctype, n+1)) - - def max_palette_colors(type, palette_name): - """ - Return the number of colors in the brewer palette - """ - if type == 'Sequential': - return 9 - elif type == 'Diverging': - return 11 - else: - # Qualitative palettes have different limits - qlimit = {'Accent': 8, 'Dark2': 8, 'Paired': 12, - 'Pastel1': 9, 'Pastel2': 8, 'Set1': 9, - 'Set2': 8, 'Set3': 12} - return qlimit[palette_name] - - type = full_type_name(type) + type = brewer_helper.full_type_name(type) if isinstance(palette, int): - palette_name = number_to_palette_name(type, palette) + palette_name = brewer_helper.number_to_name(type, palette) else: palette_name = palette - nmax = max_palette_colors(type, palette_name) + # Get the number of colors in the palette + n_max = brewer_helper.num_colors(type, palette_name) def _brewer_pal(n): # Only draw the maximum allowable colors from the palette # and fill any remaining spots with None - _n = n if n <= nmax else nmax + _n = n if n <= n_max else n_max try: bmap = colorbrewer.get_map(palette_name, type, _n) - except ValueError as err: - # Some palettes have a minimum no. of colors set at 3 + except ValueError: + # Some palettes have a minimum no. of colors # We get around that restriction. - if 0 <= _n < 3: - bmap = colorbrewer.get_map(palette_name, type, 3) - else: - raise err + n_min = brewer_helper.min_num_colors(type, palette_name) + bmap = colorbrewer.get_map(palette_name, type, n_min) hex_colors = bmap.hex_colors[:n] - if n > nmax: + if n > n_max: msg = ("Warning message:" - "Brewer palette {} has a maximum of {} colors" - "Returning the palette you asked for with" - "that many colors".format(palette_name, nmax)) + f"Brewer palette {palette_name} has a maximum " + f"of {n_max} colors Returning the palette you " + "asked for with that many colors") warnings.warn(msg) - hex_colors = hex_colors + [None] * (n - nmax) + hex_colors = hex_colors + [None] * (n - n_max) return hex_colors[::direction] return _brewer_pal @@ -467,10 +425,14 @@ values = [values] color_tuples = colormap(values) - try: - hex_colors = [mcolors.rgb2hex(t) for t in color_tuples] - except IndexError: - hex_colors = mcolors.rgb2hex(color_tuples) + hex_colors = [mcolors.rgb2hex(t) for t in color_tuples] + + nan_bool_idx = pd.isnull(values) | np.isinf(values) + if any(nan_bool_idx): + hex_colors = [ + np.nan if is_nan else color + for color, is_nan in zip(hex_colors, nan_bool_idx) + ] return hex_colors if iterable else hex_colors[0] @@ -503,6 +465,8 @@ >>> palette = gradient_n_pal(['red', 'blue']) >>> palette([0, .25, .5, .75, 1]) ['#ff0000', '#bf0040', '#7f0080', '#3f00c0', '#0000ff'] + >>> palette([-np.inf, 0, np.nan, 1, np.inf]) + [nan, '#ff0000', nan, '#0000ff', nan] """ # Note: For better results across devices and media types, # it would be better to do the interpolation in @@ -679,7 +643,7 @@ def _manual_pal(n): if n > max_n: msg = ("Palette can return a maximum of {} values. " - "{} were requested from it.") + "{} values requested.") warnings.warn(msg.format(max_n, n)) return values[:n] @@ -822,3 +786,60 @@ [2, 4, 6] """ return identity + + +def _first_last(it): + """ + First and Last value of iterator as integers + """ + lst = list(it) + return int(lst[0]), int(lst[-1]) + + +class brewer_helper: + """ + Helper function for useing colorbrewer + """ + _ncolor_range = { + t: { + palette: _first_last(info.keys()) + for palette, info in colorbrewer.COLOR_MAPS[t].items() + } + for t in colorbrewer.COLOR_MAPS + } + + @classmethod + def num_colors(cls, type, palette): + return cls._ncolor_range[type][palette][1] + + @classmethod + def min_num_colors(cls, type, palette): + return cls._ncolor_range[type][palette][0] + + @staticmethod + def full_type_name(text): + abbrevs = { + 'seq': 'Sequential', + 'qual': 'Qualitative', + 'div': 'Diverging' + } + text = abbrevs.get(text, text) + return text.title() + + @staticmethod + def number_to_name(ctype, n): + """ + Return palette name that corresponds to a given number + + Uses alphabetical ordering + """ + _n = n - 1 + palettes = sorted(colorbrewer.COLOR_MAPS[ctype].keys()) + if _n < len(palettes): + return palettes[_n] + + npalettes = len(palettes) + raise ValueError( + f"There are only '{npalettes}' palettes of type {ctype}. " + f"You requested palette no. {n}" + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/scale.py new/mizani-0.7.1/mizani/scale.py --- old/mizani-0.6.0/mizani/scale.py 2018-10-11 15:57:40.000000000 +0200 +++ new/mizani-0.7.1/mizani/scale.py 2020-06-05 00:46:31.000000000 +0200 @@ -33,7 +33,7 @@ from .bounds import censor, rescale from .utils import CONTINUOUS_KINDS, DISCRETE_KINDS, min_max, match -from .utils import multitype_sort +from .utils import get_categories __all__ = ['scale_continuous', 'scale_discrete'] @@ -190,6 +190,8 @@ if old is None: old = [] + else: + old = list(old) # Get the missing values (NaN & Nones) locations and remove them nan_bool_idx = pd.isnull(new_data) @@ -204,29 +206,30 @@ # Train i.e. get the new values if pdtypes.is_categorical_dtype(new_data): - try: - new = list(new_data.cat.categories) # series - except AttributeError: - new = list(new_data.categories) # plain categorical + categories = get_categories(new_data) if drop: present = set(new_data.drop_duplicates()) - new = [i for i in new if i in present] + new = [i for i in categories if i in present] + else: + new = list(categories) else: - try: - new = np.unique(new_data) - new.sort() - except TypeError: - # new_data probably has nans and other types - new = list(set(new_data)) - new = multitype_sort(new) - - # Add nan if required - if has_na and not na_rm: - new = np.hstack([new, np.nan]) + new = np.unique(new_data) + new.sort() # update old old_set = set(old) - return list(old) + [i for i in new if (i not in old_set)] + if pdtypes.is_categorical_dtype(new_data): + # The limits are in the order of the categories + all_set = old_set | set(new) + ordered_cats = categories.union(old, sort=False) + limits = [c for c in ordered_cats if c in all_set] + else: + limits = old + [i for i in new if (i not in old_set)] + + # Add nan if required + if has_na and not na_rm: + limits.append(np.nan) + return limits @classmethod def map(cls, x, palette, limits, na_value=None): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/tests/test_breaks.py new/mizani-0.7.1/mizani/tests/test_breaks.py --- old/mizani-0.6.0/mizani/tests/test_breaks.py 2019-07-10 13:51:46.000000000 +0200 +++ new/mizani-0.7.1/mizani/tests/test_breaks.py 2020-06-04 13:23:00.000000000 +0200 @@ -65,6 +65,40 @@ breaks = log_breaks()([1761, 8557]) npt.assert_array_equal(breaks, [1000, 2000, 3000, 5000, 10000]) + # log_breaks -> _log_sub_breaks -> extended_breaks + breaks = log_breaks(13)([1, 10]) + npt.assert_array_almost_equal( + breaks, + np.arange(0, 11) + ) + + # No overflow effects + breaks = log_breaks(n=6)([1e25, 1e30]) + npt.assert_array_almost_equal( + breaks, + [1e25, 1e26, 1e27, 1e28, 1e29, 1e30] + ) + + # No overflow effects in _log_sub_breaks + breaks = log_breaks()([2e19, 8e19]) + npt.assert_array_almost_equal( + breaks, + [1.e+19, 2.e+19, 3.e+19, 5.e+19, 1.e+20] + ) + + # _log_sub_breaks for base != 10 + breaks = log_breaks(n=5, base=60)([2e5, 8e5]) + npt.assert_array_almost_equal( + breaks, + [129600, 216000, 432000, 648000, 1080000] + ) + + breaks = log_breaks(n=5, base=2)([20, 80]) + npt.assert_array_almost_equal( + breaks, + [16, 32, 64, 128] + ) + def test_minor_breaks(): # equidistant breaks @@ -143,6 +177,16 @@ t = log_trans(base) assert len(t.minor_breaks(breaks, limits)) == base - 2 + t = log_trans() + major = t.transform([1, 10, 100]) + limits = t.transform([1, 100]) + result = trans_minor_breaks(t)(major, limits, n=4) + npt.assert_allclose( + result, + [1.02961942, 1.5260563, 1.85629799, 2.10413415, + 3.33220451, 3.8286414, 4.15888308, 4.40671925] + ) + def test_date_breaks(): # cpython diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/tests/test_formatters.py new/mizani-0.7.1/mizani/tests/test_formatters.py --- old/mizani-0.6.0/mizani/tests/test_formatters.py 2019-08-15 14:14:43.000000000 +0200 +++ new/mizani-0.7.1/mizani/tests/test_formatters.py 2020-06-04 13:23:00.000000000 +0200 @@ -82,7 +82,6 @@ def test_log_format(): formatter = log_format() - assert formatter([0.001, 0.1, 100]) == ['0.001', '0.1', '100'] assert formatter([0.001, 0.1, 10000]) == ['1e-3', '1e-1', '1e4'] assert formatter([35, 60]) == ['35', '60'] @@ -92,6 +91,8 @@ assert formatter([1, 35, 60, 1000]) == ['1', '35', '60', '1000'] assert formatter([1, 35, 60, 10000]) == ['1', '35', '60', '10000'] assert formatter([3.000000000000001e-05]) == ['3e-5'] + assert formatter([1, 1e4]) == ['1', '1e4'] + assert formatter([1, 35, 60, 1e6]) == ['1', '4e1', '6e1', '1e6'] formatter = log_format(base=2) assert formatter([1, 10, 11, 1011]) == ['1', '10', '11', '1011'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/tests/test_palettes.py new/mizani-0.7.1/mizani/tests/test_palettes.py --- old/mizani-0.6.0/mizani/tests/test_palettes.py 2019-08-15 14:14:43.000000000 +0200 +++ new/mizani-0.7.1/mizani/tests/test_palettes.py 2020-06-04 13:23:00.000000000 +0200 @@ -1,7 +1,7 @@ import pytest import numpy as np import numpy.testing as npt - +from matplotlib.cm import get_cmap from mizani.palettes import (hls_palette, husl_palette, rescale_pal, area_pal, abs_area, grey_pal, hue_pal, @@ -9,6 +9,7 @@ cmap_d_pal, desaturate_pal, manual_pal, xkcd_palette, crayon_palette, cubehelix_pal, identity_pal) +from mizani.palettes import ratios_to_colors def test_hls_palette(): @@ -205,3 +206,9 @@ value = palette(10) assert value == 10 + + +def test_ratios_to_colors(): + x = 0.5 + result = ratios_to_colors(x, get_cmap('viridis')) + assert result[0] == '#' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/tests/test_scale.py new/mizani-0.7.1/mizani/tests/test_scale.py --- old/mizani-0.6.0/mizani/tests/test_scale.py 2018-10-08 23:59:27.000000000 +0200 +++ new/mizani-0.7.1/mizani/tests/test_scale.py 2020-06-05 00:46:31.000000000 +0200 @@ -39,6 +39,9 @@ def assert_equal_with_nan(lst1, lst2): assert lst1[:-1] == lst2[:-1] and np.isnan(lst2[-1]) + def SCategorical(*args, **kwargs): + return pd.Series(pd.Categorical(*args, **kwargs)) + x = ['a', 'b', 'c', 'a'] # apply scaled = scale_discrete.apply(x, np.arange) @@ -87,3 +90,21 @@ limits = scale_discrete.train(x[:2], drop=False) assert limits == ['a', 'b', 'c'] + + # Disrete Scale training maintains order of categoricals + cats = ['x0', 'x1', 'x2', 'x3', 'x4'] + s1 = SCategorical(['x1', 'x2'], categories=cats) + s2 = SCategorical(['x0', 'x2'], categories=cats) + limits = scale_discrete.train(s1, drop=True) + limits = scale_discrete.train(s2, limits, drop=True) + assert limits == ['x0', 'x1', 'x2'] + + # Trainning on mixed categories, the last data determines + # the location of a value that is in two categoricals + # eg. a & e are ordered right! + x1 = pd.Categorical(['a', 'b', 'c', 'e']) + x2 = pd.Categorical(['d', 'f', 'e', 'a']) + limits = scale_discrete.train(x1) + limits = scale_discrete.train(x2, old=limits) + # assert limits == list('abcedf') + assert limits == list('adefbc') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/tests/test_transforms.py new/mizani-0.7.1/mizani/tests/test_transforms.py --- old/mizani-0.6.0/mizani/tests/test_transforms.py 2019-08-15 14:14:43.000000000 +0200 +++ new/mizani-0.7.1/mizani/tests/test_transforms.py 2020-06-04 13:23:00.000000000 +0200 @@ -96,12 +96,25 @@ def test_boxcox_trans(): - _test_trans(boxcox_trans(0), arr) _test_trans(boxcox_trans(0.5), arr*10) + _test_trans(boxcox_trans(1), arr) with pytest.raises(ValueError): x = np.arange(-4, 4) _test_trans(boxcox_trans(0.5), x) + # Special case, small p and p = 0 + with pytest.warns(RuntimeWarning): + _test_trans(boxcox_trans(1e-8), arr) + _test_trans(boxcox_trans(0), arr) + + x = [0, 1, 2, 3] + t = boxcox_trans(0) + with pytest.warns(RuntimeWarning): + xt = t.transform(x) + xti = t.inverse(xt) + assert np.isneginf(xt[0]) + npt.assert_array_almost_equal(x, xti) + def test_modulus_trans(): _test_trans(modulus_trans(0), arr) @@ -163,6 +176,11 @@ pos = [10 ** int(x) for x in p] arr = np.hstack([-np.array(pos[::-1]), pos]) _test_trans(pseudo_log_trans, arr) + _test_trans(pseudo_log_trans(base=16), arr) + _test_trans( + pseudo_log_trans(base=10, minor_breaks=minor_breaks(n=5)), + arr + ) def test_probability_trans(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/tests/test_utils.py new/mizani-0.7.1/mizani/tests/test_utils.py --- old/mizani-0.6.0/mizani/tests/test_utils.py 2019-03-26 16:25:25.000000000 +0100 +++ new/mizani-0.7.1/mizani/tests/test_utils.py 2020-06-03 21:48:57.000000000 +0200 @@ -5,7 +5,7 @@ from mizani.utils import (round_any, min_max, match, precision, first_element, multitype_sort, - same_log10_order_of_magnitude) + same_log10_order_of_magnitude, get_categories) def test_round_any(): @@ -139,3 +139,20 @@ assert same_log10_order_of_magnitude((1, 9.9), delta=0) assert same_log10_order_of_magnitude((35, 91), delta=0) assert same_log10_order_of_magnitude((232.3, 950), delta=0) + + +def test_get_categories(): + lst = list('abcd') + s = pd.Series(lst) + c = pd.Categorical(lst) + sc = pd.Series(c) + + categories = pd.Index(lst) + assert categories.equals(get_categories(c)) + assert categories.equals(get_categories(sc)) + + with pytest.raises(TypeError): + assert categories.equals(get_categories(lst)) + + with pytest.raises(TypeError): + assert categories.equals(get_categories(s)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/transforms.py new/mizani-0.7.1/mizani/transforms.py --- old/mizani-0.6.0/mizani/transforms.py 2019-08-15 14:14:43.000000000 +0200 +++ new/mizani-0.7.1/mizani/transforms.py 2020-06-04 13:23:00.000000000 +0200 @@ -435,9 +435,6 @@ :func:`~mizani.transforms.modulus_trans` """ - if np.abs(p) < 1e-7: - return log_trans() - def transform(x): x = np.asarray(x) if np.any((x + offset) < 0): @@ -608,16 +605,7 @@ """ Transform from date to a numerical format """ - try: - x = date2num(x) - except AttributeError: - # numpy datetime64 - # This is not ideal because the operations do not - # preserve the np.datetime64 type. May be need - # a datetime64_trans - x = [pd.Timestamp(item) for item in x] - x = date2num(x) - return x + return date2num(x) @staticmethod def inverse(x): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani/utils.py new/mizani-0.7.1/mizani/utils.py --- old/mizani-0.6.0/mizani/utils.py 2019-08-07 23:49:09.000000000 +0200 +++ new/mizani-0.7.1/mizani/utils.py 2020-06-04 13:23:00.000000000 +0200 @@ -6,8 +6,8 @@ __all__ = ['round_any', 'min_max', 'match', 'precision', 'first_element', 'multitype_sort', - 'is_close_to_int', 'same_log10_order_of_magnitude', - 'identity' + 'same_log10_order_of_magnitude', + 'identity', 'get_categories' ] DISCRETE_KINDS = 'ObUS' @@ -224,36 +224,6 @@ return list(chain(*(types[t] for t in types))) -def nearest_int(x): - """ - Return nearest long integer to x - """ - if x == 0: - return np.int64(0) - elif x > 0: - return np.int64(x + 0.5) - else: - return np.int64(x - 0.5) - - -def is_close_to_int(x): - """ - Check if value is close to an integer - - Parameters - ---------- - x : float - Numeric value to check - - Returns - ------- - out : bool - """ - if not np.isfinite(x): - return False - return abs(x - nearest_int(x)) < 1e-10 - - def same_log10_order_of_magnitude(x, delta=0.1): """ Return true if range is approximately in same order of magnitude @@ -282,3 +252,26 @@ Return whatever is passed in """ return args if len(args) > 1 else args[0] + + +def get_categories(x): + """ + Return the categories of x + + Parameters + ---------- + x : category_like + Input Values + + Returns + ------- + out : Index + Categories of x + """ + try: + return x.cat.categories # series + except AttributeError: + try: + return x.categories # plain categorical + except AttributeError: + raise TypeError("x is the wrong type, it has no categories") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani.egg-info/PKG-INFO new/mizani-0.7.1/mizani.egg-info/PKG-INFO --- old/mizani-0.6.0/mizani.egg-info/PKG-INFO 2019-08-15 14:38:39.000000000 +0200 +++ new/mizani-0.7.1/mizani.egg-info/PKG-INFO 2020-06-05 00:46:53.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: mizani -Version: 0.6.0 +Version: 0.7.1 Summary: Scales for Python Home-page: https://github.com/has2k1/mizani Maintainer: Hassan Kibirige diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/mizani.egg-info/requires.txt new/mizani-0.7.1/mizani.egg-info/requires.txt --- old/mizani-0.6.0/mizani.egg-info/requires.txt 2019-08-15 14:38:39.000000000 +0200 +++ new/mizani-0.7.1/mizani.egg-info/requires.txt 2020-06-05 00:46:53.000000000 +0200 @@ -1,4 +1,4 @@ numpy -pandas>=0.25.0 +pandas>=1.0.0 matplotlib>=3.1.1 palettable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/setup.cfg new/mizani-0.7.1/setup.cfg --- old/mizani-0.6.0/setup.cfg 2019-08-15 14:38:39.000000000 +0200 +++ new/mizani-0.7.1/setup.cfg 2020-06-05 00:46:54.000000000 +0200 @@ -1,6 +1,3 @@ -[wheel] -universal = 1 - [versioneer] vcs = git style = pep440 @@ -10,7 +7,7 @@ parentdir_prefix = mizani- [flake8] -ignore = E121,E123,E126,E226,E24,E704,W503,W504,E741 +ignore = E121,E123,E126,E226,E24,E704,W503,W504,E741,E743 [egg_info] tag_build = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mizani-0.6.0/setup.py new/mizani-0.7.1/setup.py --- old/mizani-0.6.0/setup.py 2019-08-15 14:15:37.000000000 +0200 +++ new/mizani-0.7.1/setup.py 2020-06-03 21:48:57.000000000 +0200 @@ -15,6 +15,12 @@ __description__ = "Scales for Python" __license__ = 'BSD (3-clause)' __url__ = 'https://github.com/has2k1/mizani' +__classifiers__ = [ + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: BSD License', + 'Programming Language :: Python :: 3', + 'Topic :: Scientific/Engineering :: Visualization', +] def check_dependencies(): @@ -31,7 +37,7 @@ Plus any version tests and warnings """ install_requires = ['numpy', - 'pandas >= 0.25.0', + 'pandas >= 1.0.0', 'matplotlib >= 3.1.1', 'palettable'] return install_requires @@ -72,10 +78,5 @@ install_requires=get_required_packages(), packages=find_packages(), package_data=get_package_data(), - classifiers=[ - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python :: 3', - 'Topic :: Scientific/Engineering :: Visualization', - ], + classifiers=__classifiers__ )
