Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions condarecipe/larray/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ requirements:
test:
requires:
- pytest
- pytables
- matplotlib-base
- openpyxl
- xlsxwriter
- pydantic >=2

imports:
- larray
Expand Down
4 changes: 2 additions & 2 deletions larray/core/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -7330,7 +7330,7 @@ def plot(self) -> PlotObject:

Line plot with grid and a title, saved in a file

>>> arr.plot(grid=True, title='line plot', filepath='my_file.png')
>>> arr.plot(grid=True, title='line plot', filepath='my_file.png') # doctest: +SKIP

2 bar plots (one for each gender) sharing the same y axis, which makes sub plots
easier to compare. By default sub plots are independant of each other and the axes
Expand All @@ -7352,7 +7352,7 @@ def plot(self) -> PlotObject:

Create a figure containing 2 x 2 graphs

>>> import matplotlib.pyplot as plt
>>> import matplotlib.pyplot as plt # doctest: +SKIP
>>> # see matplotlib.pyplot.subplots documentation for more details
>>> fig, ax = plt.subplots(2, 2, figsize=(10, 8), tight_layout=True) # doctest: +SKIP
>>> # line plot with 2 curves (Males and Females) in the top left corner (0, 0)
Expand Down
30 changes: 25 additions & 5 deletions larray/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
import numpy as np
from numpy.lib import NumpyVersion
import pandas as pd

try:
import matplotlib
except ImportError:
matplotlib = None
try:
import xlwings as xw
except ImportError:
Expand Down Expand Up @@ -141,11 +146,26 @@ def meta():
score=9.70, date=pd.Timestamp(dt.datetime(1970, 3, 21)))


needs_pytables = pytest.mark.skipif(tables is None, reason="pytables is required for this test")
needs_xlwings = pytest.mark.skipif(SKIP_EXCEL_TESTS or xw is None, reason="xlwings is required for this test")
needs_openpyxl = pytest.mark.skipif(SKIP_EXCEL_TESTS or openpyxl is None, reason="openpyxl is required for this test")
needs_xlsxwriter = pytest.mark.skipif(SKIP_EXCEL_TESTS or xlsxwriter is None,
reason="xlsxwriter is required for this test")
needs_matplotlib = (
pytest.mark.skipif(matplotlib is None,
reason="matplotlib is required for this test")
)
needs_pytables = (
pytest.mark.skipif(tables is None,
reason="pytables is required for this test")
)
needs_xlwings = (
pytest.mark.skipif(SKIP_EXCEL_TESTS or xw is None,
reason="xlwings is required for this test")
)
needs_openpyxl = (
pytest.mark.skipif(SKIP_EXCEL_TESTS or openpyxl is None,
reason="openpyxl is required for this test")
)
needs_xlsxwriter = (
pytest.mark.skipif(SKIP_EXCEL_TESTS or xlsxwriter is None,
reason="xlsxwriter is required for this test")
)


@contextmanager
Expand Down
34 changes: 20 additions & 14 deletions larray/tests/test_array.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
import os
import sys
from io import StringIO

import pytest
import numpy as np
import pandas as pd
import matplotlib.figure

from io import StringIO

from larray.tests.common import (meta, inputpath,
assert_larray_equal, assert_larray_nan_equal, assert_larray_equiv,
assert_nparray_equal, assert_nparray_nan_equal,
needs_xlwings, needs_pytables, needs_xlsxwriter, needs_openpyxl, NUMPY2,
must_warn, must_raise)
from larray import (Array, LArray, Axis, AxisCollection, LGroup, IGroup, Metadata,
zeros, zeros_like, ndtest, empty, ones, full, eye, diag, stack, sequence,
asarray, union, clip, exp, where, X, mean, inf, nan, isnan, round,
read_hdf, read_csv, read_eurostat, read_excel, open_excel,
from_lists, from_string, from_frame, from_series,
zip_array_values, zip_array_items, nan_to_num)
from larray.tests.common import (
meta, inputpath,
assert_larray_equal, assert_larray_nan_equal, assert_larray_equiv,
assert_nparray_equal, assert_nparray_nan_equal,
needs_xlwings, needs_pytables, needs_xlsxwriter, needs_openpyxl,
needs_matplotlib,
NUMPY2,
must_warn, must_raise
)
from larray import (
Array, LArray, Axis, AxisCollection, LGroup, IGroup, Metadata,
zeros, zeros_like, ndtest, empty, ones, full, eye, diag, stack, sequence,
asarray, union, clip, exp, where, X, mean, inf, nan, isnan, round,
read_hdf, read_csv, read_eurostat, read_excel, open_excel,
from_lists, from_string, from_frame, from_series,
zip_array_values, zip_array_items, nan_to_num
)
from larray.core.axis import (
_to_ticks, _to_key, _retarget_warn_msg, _group_as_aggregated_label_msg
)
Expand Down Expand Up @@ -5568,7 +5572,9 @@ def test_broadcast_with():
assert_larray_equiv(b, a2)


@needs_matplotlib
def test_plot():
import matplotlib.figure
import matplotlib.pyplot as plt

fig, ax = plt.subplots() # doctest: +SKIP
Expand Down
65 changes: 34 additions & 31 deletions larray/util/plot.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,40 @@
import numpy as np
from matplotlib.ticker import MaxNLocator

try:
from matplotlib.ticker import MaxNLocator

class MaxNMultipleWithOffsetLocator(MaxNLocator):
def __init__(self, nbins=None, offset=0.5, **kwargs):
super().__init__(nbins, **kwargs)
self.offset = offset
class MaxNMultipleWithOffsetLocator(MaxNLocator):
def __init__(self, nbins=None, offset=0.5, **kwargs):
super().__init__(nbins, **kwargs)
self.offset = offset

def tick_values(self, vmin, vmax):
# matplotlib calls them vmin and vmax but they are actually the limits and vmin can be > vmax
invert = vmin > vmax
if invert:
vmin, vmax = vmax, vmin
def tick_values(self, vmin, vmax):
# matplotlib calls them vmin and vmax but they are actually the limits and vmin can be > vmax
invert = vmin > vmax
if invert:
vmin, vmax = vmax, vmin

max_desired_ticks = self._nbins
# not + 1 because we place ticks in the middle
num_ticks = vmax - vmin
desired_numticks = min(num_ticks, max_desired_ticks)
if desired_numticks < num_ticks:
step = np.ceil(num_ticks / desired_numticks)
else:
step = 1
vmin = int(vmin)
vmax = int(vmax)
# when we have an offset, we do not add 1 to vmax because we place ticks in the middle
# (by adding the offset), and would result in the last "tick" being outside the limits
stop = vmax + 1 if self.offset == 0 else vmax
new_ticks = np.arange(vmin, stop, step)
if invert:
new_ticks = new_ticks[::-1]
return new_ticks + self.offset
max_desired_ticks = self._nbins
# not + 1 because we place ticks in the middle
num_ticks = vmax - vmin
desired_numticks = min(num_ticks, max_desired_ticks)
if desired_numticks < num_ticks:
step = np.ceil(num_ticks / desired_numticks)
else:
step = 1
vmin = int(vmin)
vmax = int(vmax)
# when we have an offset, we do not add 1 to vmax because we place ticks in the middle
# (by adding the offset), and would result in the last "tick" being outside the limits
stop = vmax + 1 if self.offset == 0 else vmax
new_ticks = np.arange(vmin, stop, step)
if invert:
new_ticks = new_ticks[::-1]
return new_ticks + self.offset

def __call__(self):
"""Return the locations of the ticks."""
vmin, vmax = self.axis.get_view_interval()
return self.tick_values(vmin, vmax)
def __call__(self):
"""Return the locations of the ticks."""
vmin, vmax = self.axis.get_view_interval()
return self.tick_values(vmin, vmax)
except ImportError:
pass