Skip to content

Commit

Permalink
Merge pull request #152 from arvkevi/issue-150-add-readthedocs-config
Browse files Browse the repository at this point in the history
Update rtd
  • Loading branch information
arvkevi committed Jul 9, 2023
2 parents cff906a + 492ef99 commit ba217b7
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 127 deletions.
36 changes: 22 additions & 14 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@
#
import os
import sys
sys.path.insert(0, os.path.abspath('..'))

sys.path.insert(0, os.path.abspath(".."))

import kneed


# -- Project information -----------------------------------------------------

project = 'kneed'
copyright = '2020, Kevin Arvai'
author = 'Kevin Arvai'
project = "kneed"
copyright = "2020, Kevin Arvai"
author = "Kevin Arvai"

# The full version, including alpha/beta/rc tags
release = '0.6.0'
release = kneed.__version__

version = kneed.__version__


# -- General configuration ---------------------------------------------------
Expand All @@ -31,19 +36,22 @@
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.coverage',
'sphinx.ext.napoleon',
'sphinx_rtd_theme'
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.coverage",
"sphinx.ext.napoleon",
"sphinx_rtd_theme",
]

pygments_style = "sphinx"

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]


# -- Options for HTML output -------------------------------------------------
Expand All @@ -56,8 +64,8 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = []

autoclass_content = 'both'
autoclass_content = "both"

master_doc = 'index'
master_doc = "index"
7 changes: 4 additions & 3 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ Welcome to kneed's documentation!

This is the documentation for the `kneed <https://github.com/arvkevi/kneed>`__ Python package.
Given `x` and `y` arrays, `kneed` attempts to identify the knee/elbow point of a line fit to the data.
The knee/elbow is defined as the point of the line with maximum curvature. For more information about how each of
the parameters affect identification of knee points, check out :ref:`parameters`. For a full reference of the API,
head over to the :ref:`api`.
The knee/elbow is defined as the point of the line with maximum curvature.

For more information about how each of the parameters affect identification of knee points, check out :ref:`parameters`.
For a full reference of the API, head over to the :ref:`api`.

.. toctree::
parameters
Expand Down
4 changes: 1 addition & 3 deletions docs/interactive.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ Interactive Streamlit App
=========================

An interactive streamlit app was developed to help users explore the effect of tuning the parameters.
There are two sites where you can test out kneed by copy-pasting your own data:

1. https://share.streamlit.io/arvkevi/ikneed/main/ikneed.py
2. https://ikneed.herokuapp.com/
https://share.streamlit.io/arvkevi/ikneed/main/ikneed.py

You can also run your own version -- head over to the source code for ikneed_.

Expand Down
9 changes: 9 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
sphinx==6.2.1
sphinx_rtd_theme==1.2.2
sphinxcontrib-applehelp==1.0.4
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.1
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
203 changes: 109 additions & 94 deletions kneed/knee_locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
import matplotlib.pyplot as plt
except ImportError:
_has_matplotlib = False
_matplotlib_not_found_err = ModuleNotFoundError("This function needs Matplotlib to be executed. Please run command `pip install kneed[plot]` ")
_matplotlib_not_found_err = ModuleNotFoundError(
"This function needs Matplotlib to be executed. Please run command `pip install kneed[plot]` "
)
else:
_has_matplotlib = True


class KneeLocator(object):
"""
Once instantiated, this class attempts to find the point of maximum
Expand All @@ -24,7 +27,7 @@ class KneeLocator(object):
:type x: 1D array of shape (`number_of_y_values`,) or list
:param y: y values, must be the same length as x.
:type y: 1D array of shape (`number_of_y_values`,) or list
:param S: Sensitivity, original paper suggests default of 1.0
:param S: Sensitivity, the number of minimum number of data points below the local distance maximum before calling a knee. The original paper suggests default of 1.0
:type S: float
:param curve: If 'concave', algorithm will detect knees. If 'convex', it
will detect elbows.
Expand All @@ -37,6 +40,93 @@ class KneeLocator(object):
:type online: bool
:param polynomial_degree: The degree of the fitting polynomial. Only used when interp_method="polynomial". This argument is passed to numpy polyfit `deg` parameter.
:type polynomial_degree: int
:ivar x: x values.
:vartype x: array-like
:ivar y: y values.
:vartype y: array-like
:ivar S: Sensitivity, original paper suggests default of 1.0
:vartype S: integer
:ivar curve: If 'concave', algorithm will detect knees. If 'convex', it
will detect elbows.
:vartype curve: str
:ivar direction: one of {"increasing", "decreasing"}
:vartype direction: str
:ivar interp_method: one of {"interp1d", "polynomial"}
:vartype interp_method: str
:ivar online: kneed will correct old knee points if True, will return first knee if False
:vartype online: str
:ivar polynomial_degree: The degree of the fitting polynomial. Only used when interp_method="polynomial". This argument is passed to numpy polyfit `deg` parameter.
:vartype polynomial_degree: int
:ivar N: The number of `x` values in the
:vartype N: integer
:ivar all_knees: A set containing all the x values of the identified knee points.
:vartype all_knees: set
:ivar all_norm_knees: A set containing all the normalized x values of the identified knee points.
:vartype all_norm_knees: set
:ivar all_knees_y: A list containing all the y values of the identified knee points.
:vartype all_knees_y: list
:ivar all_norm_knees_y: A list containing all the normalized y values of the identified knee points.
:vartype all_norm_knees_y: list
:ivar Ds_y: The y values from the fitted spline.
:vartype Ds_y: numpy array
:ivar x_normalized: The normalized x values.
:vartype x_normalized: numpy array
:ivar y_normalized: The normalized y values.
:vartype y_normalized: numpy array
:ivar x_difference: The x values of the difference curve.
:vartype x_difference: numpy array
:ivar y_difference: The y values of the difference curve.
:vartype y_difference: numpy array
:ivar maxima_indices: The indices of each of the maxima on the difference curve.
:vartype maxima_indices: numpy array
:ivar maxima_indices: The indices of each of the maxima on the difference curve.
:vartype maxima_indices: numpy array
:ivar x_difference_maxima: The x values from the difference curve where the local maxima are located.
:vartype x_difference_maxima: numpy array
:ivar y_difference_maxima: The y values from the difference curve where the local maxima are located.
:vartype y_difference_maxima: numpy array
:ivar minima_indices: The indices of each of the minima on the difference curve.
:vartype minima_indices: numpy array
:ivar minima_indices: The indices of each of the minima on the difference curve.
:vartype maxima_indices: numpy array
:ivar x_difference_minima: The x values from the difference curve where the local minima are located.
:vartype x_difference_minima: numpy array
:ivar y_difference_minima: The y values from the difference curve where the local minima are located.
:vartype y_difference_minima: numpy array
:ivar Tmx: The y values that correspond to the thresholds on the difference curve for determining the knee point.
:vartype Tmx: numpy array
:ivar knee: The x value of the knee point.
:vartype knee: float
:ivar knee_y: The y value of the knee point.
:vartype knee_y: float
:ivar norm_knee: The normalized x value of the knee point.
:vartype norm_knee: float
:ivar norm_knee_y: The normalized y value of the knee point.
:vartype norm_knee_y: float
:ivar all_knees: The x values of all the identified knee points.
:vartype all_knees: set
:ivar all_knees_y: The y values of all the identified knee points.
:vartype all_knees: set
:ivar all_norm_knees: The normalized x values of all the identified knee points.
:vartype all_norm_knees: set
:ivar all_norm_knees_y: The normalized y values of all the identified knee points.
:vartype all_norm_knees: set
:ivar elbow: The x value of the elbow point (elbow and knee are interchangeable).
:vartype elbow: float
:ivar elbow_y: The y value of the knee point (elbow and knee are interchangeable).
:vartype elbow_y: float
:ivar norm_elbow: The normalized x value of the knee point (elbow and knee are interchangeable).
:vartype norm_knee: float
:ivar norm_elbow_y: The normalized y value of the knee point (elbow and knee are interchangeable).
:vartype norm_elbow_y: float
:ivar all_elbows: The x values of all the identified knee points (elbow and knee are interchangeable).
:vartype all_elbows: set
:ivar all_elbows_y: The y values of all the identified knee points (elbow and knee are interchangeable).
:vartype all_elbows: set
:ivar all_norm_elbows: The normalized x values of all the identified knee points (elbow and knee are interchangeable).
:vartype all_norm_elbows: set
:ivar all_norm_elbows_y: The normalized y values of all the identified knee points (elbow and knee are interchangeable).
:vartype all_norm_elbows: set
"""

def __init__(
Expand All @@ -50,95 +140,6 @@ def __init__(
online: bool = False,
polynomial_degree: int = 7,
):
"""
:ivar x: x values.
:vartype x: array-like
:ivar y: y values.
:vartype y: array-like
:ivar S: Sensitivity, original paper suggests default of 1.0
:vartype S: integer
:ivar curve: If 'concave', algorithm will detect knees. If 'convex', it
will detect elbows.
:vartype curve: str
:ivar direction: one of {"increasing", "decreasing"}
:vartype direction: str
:ivar interp_method: one of {"interp1d", "polynomial"}
:vartype interp_method: str
:ivar online: kneed will correct old knee points if True, will return first knee if False
:vartype online: str
:ivar polynomial_degree: The degree of the fitting polynomial. Only used when interp_method="polynomial". This argument is passed to numpy polyfit `deg` parameter.
:vartype polynomial_degree: int
:ivar N: The number of `x` values in the
:vartype N: integer
:ivar all_knees: A set containing all the x values of the identified knee points.
:vartype all_knees: set
:ivar all_norm_knees: A set containing all the normalized x values of the identified knee points.
:vartype all_norm_knees: set
:ivar all_knees_y: A list containing all the y values of the identified knee points.
:vartype all_knees_y: list
:ivar all_norm_knees_y: A list containing all the normalized y values of the identified knee points.
:vartype all_norm_knees_y: list
:ivar Ds_y: The y values from the fitted spline.
:vartype Ds_y: numpy array
:ivar x_normalized: The normalized x values.
:vartype x_normalized: numpy array
:ivar y_normalized: The normalized y values.
:vartype y_normalized: numpy array
:ivar x_difference: The x values of the difference curve.
:vartype x_difference: numpy array
:ivar y_difference: The y values of the difference curve.
:vartype y_difference: numpy array
:ivar maxima_indices: The indices of each of the maxima on the difference curve.
:vartype maxima_indices: numpy array
:ivar maxima_indices: The indices of each of the maxima on the difference curve.
:vartype maxima_indices: numpy array
:ivar x_difference_maxima: The x values from the difference curve where the local maxima are located.
:vartype x_difference_maxima: numpy array
:ivar y_difference_maxima: The y values from the difference curve where the local maxima are located.
:vartype y_difference_maxima: numpy array
:ivar minima_indices: The indices of each of the minima on the difference curve.
:vartype minima_indices: numpy array
:ivar minima_indices: The indices of each of the minima on the difference curve.
:vartype maxima_indices: numpy array
:ivar x_difference_minima: The x values from the difference curve where the local minima are located.
:vartype x_difference_minima: numpy array
:ivar y_difference_minima: The y values from the difference curve where the local minima are located.
:vartype y_difference_minima: numpy array
:ivar Tmx: The y values that correspond to the thresholds on the difference curve for determining the knee point.
:vartype Tmx: numpy array
:ivar knee: The x value of the knee point.
:vartype knee: float
:ivar knee_y: The y value of the knee point.
:vartype knee_y: float
:ivar norm_knee: The normalized x value of the knee point.
:vartype norm_knee: float
:ivar norm_knee_y: The normalized y value of the knee point.
:vartype norm_knee_y: float
:ivar all_knees: The x values of all the identified knee points.
:vartype all_knees: set
:ivar all_knees_y: The y values of all the identified knee points.
:vartype all_knees: set
:ivar all_norm_knees: The normalized x values of all the identified knee points.
:vartype all_norm_knees: set
:ivar all_norm_knees_y: The normalized y values of all the identified knee points.
:vartype all_norm_knees: set
:ivar elbow: The x value of the elbow point (elbow and knee are interchangeable).
:vartype elbow: float
:ivar elbow_y: The y value of the knee point (elbow and knee are interchangeable).
:vartype elbow_y: float
:ivar norm_elbow: The normalized x value of the knee point (elbow and knee are interchangeable).
:vartype norm_knee: float
:ivar norm_elbow_y: The normalized y value of the knee point (elbow and knee are interchangeable).
:vartype norm_elbow_y: float
:ivar all_elbows: The x values of all the identified knee points (elbow and knee are interchangeable).
:vartype all_elbows: set
:ivar all_elbows_y: The y values of all the identified knee points (elbow and knee are interchangeable).
:vartype all_elbows: set
:ivar all_norm_elbows: The normalized x values of all the identified knee points (elbow and knee are interchangeable).
:vartype all_norm_elbows: set
:ivar all_norm_elbowss_y: The normalized y values of all the identified knee points (elbow and knee are interchangeable).
:vartype all_norm_elbows: set
"""
# Step 0: Raw Input
self.x = np.array(x)
self.y = np.array(y)
Expand Down Expand Up @@ -238,7 +239,9 @@ def transform_y(y: Iterable[float], direction: str, curve: str) -> float:

return y

def find_knee(self,):
def find_knee(
self,
):
"""This function is called when KneeLocator is instantiated. It identifies the knee value and sets the instance attributes."""
if not self.maxima_indices.size:
warnings.warn(
Expand Down Expand Up @@ -313,7 +316,13 @@ def find_knee(self,):

return knee, norm_knee

def plot_knee_normalized(self, figsize: Optional[Tuple[int, int]] = None, title: str = "Normalized Knee Point", xlabel: Optional[str] = None, ylabel: Optional[str] = None):
def plot_knee_normalized(
self,
figsize: Optional[Tuple[int, int]] = None,
title: str = "Normalized Knee Point",
xlabel: Optional[str] = None,
ylabel: Optional[str] = None,
):
"""Plot the normalized curve, the difference curve (x_difference, y_normalized) and the knee, if it exists.
:param figsize: Optional[Tuple[int, int]
Expand Down Expand Up @@ -356,7 +365,13 @@ def plot_knee_normalized(self, figsize: Optional[Tuple[int, int]] = None, title:
)
plt.legend(loc="best")

def plot_knee(self, figsize: Optional[Tuple[int, int]] = None, title: str = "Knee Point", xlabel: Optional[str] = None, ylabel: Optional[str] = None):
def plot_knee(
self,
figsize: Optional[Tuple[int, int]] = None,
title: str = "Knee Point",
xlabel: Optional[str] = None,
ylabel: Optional[str] = None,
):
"""
Plot the curve and the knee, if it exists
Expand Down
8 changes: 4 additions & 4 deletions kneed/shape_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ def find_shape(x, y):
x1, x2 = int(len(x) * 0.2), int(len(x) * 0.8)
q = np.mean(y[x1:x2]) - np.mean(x[x1:x2] * p[0] + p[1])
if p[0] > 0 and q > 0:
return 'increasing', 'concave'
return "increasing", "concave"
if p[0] > 0 and q <= 0:
return 'increasing', 'convex'
return "increasing", "convex"
if p[0] <= 0 and q > 0:
return 'decreasing', 'concave'
return 'decreasing', 'convex'
return "decreasing", "concave"
return "decreasing", "convex"
24 changes: 24 additions & 0 deletions readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.11"

# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py

# We recommend specifying your dependencies to enable reproducible builds:
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: docs/requirements.txt
- method: pip
path: .
Loading

0 comments on commit ba217b7

Please sign in to comment.