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
3 changes: 2 additions & 1 deletion .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ jobs:
-n auto \
--color yes \
--cov mapclassify --cov-report xml --cov-append \
--doctest-only mapclassify
--doctest-only \
--mpl mapclassify

- name: codecov (${{ matrix.os }}, ${{ matrix.environment-file }})
uses: codecov/codecov-action@v4
Expand Down
1 change: 1 addition & 0 deletions ci/310-numba.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies:
- pytest
- pytest-cov
- pytest-xdist
- pytest-mpl
- codecov
- matplotlib
# optional
Expand Down
1 change: 1 addition & 0 deletions ci/310.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ dependencies:
- pytest
- pytest-cov
- pytest-xdist
- pytest-mpl
- codecov
- matplotlib
1 change: 1 addition & 0 deletions ci/311-numba.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies:
- pytest
- pytest-cov
- pytest-xdist
- pytest-mpl
- codecov
- matplotlib
# optional
Expand Down
1 change: 1 addition & 0 deletions ci/311.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies:
- pytest
- pytest-cov
- pytest-xdist
- pytest-mpl
- codecov
- matplotlib
# docs
Expand Down
1 change: 1 addition & 0 deletions ci/312-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dependencies:
- pytest
- pytest-cov
- pytest-xdist
- pytest-mpl
- codecov
# optional
- pyproj
Expand Down
1 change: 1 addition & 0 deletions ci/312-numba.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies:
- pytest-cov
- pytest-xdist
- pytest-doctestplus
- pytest-mpl
- codecov
- matplotlib
# optional
Expand Down
1 change: 1 addition & 0 deletions ci/312.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies:
- pytest
- pytest-cov
- pytest-xdist
- pytest-mpl
- codecov
- matplotlib
# docs
Expand Down
60 changes: 60 additions & 0 deletions mapclassify/classifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,66 @@ def plot(
plt.savefig(file_name, dpi=dpi)
return f, ax

def plot_histogram(
self,
color="dodgerblue",
linecolor="black",
linewidth=None,
ax=None,
despine=True,
**kwargs,
):
"""Plot histogram of `y` with bin values superimposed

Parameters
----------
color : str, optional
hue to color bars of the histogram, by default "dodgerblue".
linecolor : str, optional
color of the lines demarcating each class bin, by default "black"
linewidth : int, optional
change the linewidth demarcating each class bin
ax : matplotlib.Axes, optional
axes object to plot onto, by default None
despine : bool, optional
If True, to use seaborn's despine function to remove top and right axes,
default is True
kwargs : dict, optional
additional keyword arguments passed to matplotlib.axes.Axes.hist, by default
None

Returns
-------
matplotlib.Axes
an Axes object with histogram and class bins

Raises
------
ImportError
depends matplotlib and rasies if not installed
"""
try:
import matplotlib.pyplot as plt

if ax is None:
_, ax = plt.subplots()
except ImportError as e:
raise ImportError from e(
"You must have matplotlib available to use this function"
)
# plot `y` as a histogram
ax.hist(self.y, color=color, **kwargs)
# get the top of the ax so we know how high to raise each class bar
lim = ax.get_ylim()[1]
# plot upper limit of each bin
for i in self.bins:
ax.vlines(i, 0, lim, color=linecolor, linewidth=linewidth)
# despine if specified
if despine:
ax.spines["right"].set_visible(False)
ax.spines["top"].set_visible(False)
return ax


class HeadTailBreaks(MapClassifier):
"""
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions mapclassify/tests/test_mapclassify.py
Original file line number Diff line number Diff line change
Expand Up @@ -736,3 +736,26 @@ def test_pooled_bad_classifier(self):
message = f"'{classifier}' not a valid classifier."
with pytest.raises(ValueError, match=message):
Pooled(self.data, classifier=classifier, k=4)


class TestPlots:
def setup_method(self):
n = 20
self.data = numpy.array([numpy.arange(n) + i * n for i in range(1, 4)]).T

@pytest.mark.mpl_image_compare
def test_histogram_plot(self):
ax = Quantiles(self.data).plot_histogram()
return ax.get_figure()

@pytest.mark.mpl_image_compare
def test_histogram_plot_despine(self):
ax = Quantiles(self.data).plot_histogram(despine=False)
return ax.get_figure()

@pytest.mark.mpl_image_compare
def test_histogram_plot_linewidth(self):
ax = Quantiles(self.data).plot_histogram(
linewidth=3, linecolor="red", color="yellow"
)
return ax.get_figure()
26 changes: 9 additions & 17 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ build-backend = "setuptools.build_meta"
name = "mapclassify"
dynamic = ["version"]
maintainers = [
{name = "Serge Rey", email = "sjsrey@gmail.com"},
{name = "Wei Kang", email = "weikang9009@gmail.com"},
{ name = "Serge Rey", email = "sjsrey@gmail.com" },
{ name = "Wei Kang", email = "weikang9009@gmail.com" },
]
license = {text = "BSD 3-Clause"}
license = { text = "BSD 3-Clause" }
description = "Classification Schemes for Choropleth Maps."
keywords = ["spatial statistics", "geovisualization"]
readme = {text = """\
readme = { text = """\
`mapclassify` implements a family of classification schemes for choropleth maps.
Its focus is on the determination of the number of classes, and the assignment
of observations to those classes. It is intended for use with upstream mapping
Expand All @@ -26,7 +26,7 @@ For further theoretical background see "`Choropleth Mapping`_" in Rey, S.J., D.
.. _geopandas: https://geopandas.org/mapping.html
.. _geoplot: https://residentmario.github.io/geoplot/user_guide/Customizing_Plots.html
.. _Choropleth Mapping: https://geographicdata.science/book/notebooks/05_choropleth.html
""", content-type = "text/x-rst"}
""", content-type = "text/x-rst" }
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
Expand All @@ -52,14 +52,8 @@ Home = "https://pysal.org/mapclassify/"
Repository = "https://github.com/pysal/mapclassify"

[project.optional-dependencies]
speedups = [
"numba>=0.54",
]
dev = [
"black",
"ruff",
"pre-commit",
]
speedups = ["numba>=0.54"]
dev = ["black", "ruff", "pre-commit"]
docs = [
"nbsphinx",
"numpydoc",
Expand All @@ -76,14 +70,12 @@ tests = [
"pytest-cov",
"pytest-xdist",
"pytest-doctestplus",
"pytest-mpl"
]
all = ["numba[speedups,dev,docs,tests]"]

[tool.setuptools.packages.find]
include = [
"mapclassify",
"mapclassify.*",
]
include = ["mapclassify", "mapclassify.*"]

[tool.black]
line-length = 88
Expand Down