Skip to content

Commit

Permalink
Merge pull request #216 from knaaptime/hist
Browse files Browse the repository at this point in the history
plot histogram with class bins
  • Loading branch information
knaaptime authored Jul 3, 2024
2 parents dc8d97e + 61c7c25 commit af76ab3
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 18 deletions.
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

0 comments on commit af76ab3

Please sign in to comment.