diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4d76262..c84bfb8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,14 +1,89 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Jose D. Montoya # -# SPDX-License-Identifier: MIT +# SPDX-License-Identifier: Unlicense name: Build CI -on: [pull_request, push] +on: + pull_request: + types: [opened, reopened] + push: jobs: - test: + build-wheel: runs-on: ubuntu-latest steps: - - name: Run Build CI workflow - uses: jposada202020/workflows-circuitpython-libs/build@main + - uses: actions/setup-python@v4 + with: + python-version: "3.x" + + - uses: actions/checkout@v3 + + - name: Build wheel + run: pip wheel -w dist --no-deps . + + - name: check dist + run: pipx run twine check dist/* + + - name: Archive wheel + uses: actions/upload-artifact@v4 + with: + name: wheel + path: ${{ github.workspace }}/dist/ + + linters: + runs-on: ubuntu-latest + steps: + + - uses: actions/setup-python@v4 + with: + python-version: "3.x" + + - uses: actions/checkout@v3 + + - name: Install pre-commit and deps + run: pip install pre-commit -r requirements.txt + + - name: Setup problem matchers + uses: adafruit/circuitpython-action-library-ci-problem-matchers@v1 + + - name: Pre-commit hooks + run: pre-commit run --all-files + + build-bundles: + runs-on: ubuntu-latest + steps: + - name: Translate Repo Name For Build Tools filename_prefix + id: repo-name + run: | + echo repo-name=$( + echo ${{ github.repository }} | + awk -F '\/' '{ print tolower($2) }' | + tr '_' '-' + ) >> $GITHUB_OUTPUT + + - uses: actions/checkout@v3 + + - name: Set up Python 3.x + uses: actions/setup-python@v4 + with: + python-version: "3.x" + + - name: Checkout tools repo + uses: actions/checkout@v3 + with: + repository: adafruit/actions-ci-circuitpython-libs + path: actions-ci + + - name: Install deps + run: | + source actions-ci/install.sh + + - name: Build assets + run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location . + + - name: Archive bundles + uses: actions/upload-artifact@v4 + with: + name: bundles + path: ${{ github.workspace }}/bundles/ diff --git a/.github/workflows/release_pypi.yml b/.github/workflows/release_pypi.yml index 65775b7..160fce3 100644 --- a/.github/workflows/release_pypi.yml +++ b/.github/workflows/release_pypi.yml @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries +# SPDX-FileCopyrightText: 2025 Jose D. Montoya # # SPDX-License-Identifier: MIT @@ -9,11 +9,28 @@ on: types: [published] jobs: - upload-release-assets: + pypi-publish: + name: Publish release to PyPI runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/circuitpython-uplot + permissions: + id-token: write steps: - - name: Run PyPI Release CI workflow - uses: adafruit/workflows-circuitpython-libs/release-pypi@main - with: - pypi-username: ${{ secrets.pypi_username }} - pypi-password: ${{ secrets.pypi_password }} + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.x" + - name: Install dependencies + shell: bash + run: | + python -m pip install --upgrade pip + pip install --upgrade build + - name: Build package + run: | + find -type f -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) -exec sed -i -e "s/0.0.0+auto.0/${{github.event.release.tag_name}}/" {} + + python -m build + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.gitignore b/.gitignore index 929fe03..52ca3dd 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ _build .vscode *~ mpy-cross +.ipynb_checkpoints diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d000ade..c0e8ede 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,27 +1,30 @@ -# SPDX-FileCopyrightText: 2023 Jose D. Montoya +# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò # # SPDX-License-Identifier: Unlicense repos: - repo: https://github.com/python/black - rev: 23.3.0 + rev: 24.10.0 hooks: - id: black - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v5.0.0 hooks: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace + - id: mixed-line-ending + args: + - --fix=lf - repo: https://github.com/pycqa/pylint - rev: v2.17.4 + rev: v3.3.1 hooks: - id: pylint name: pylint (library code) types: [python] args: - --disable=consider-using-f-string - exclude: "^(docs/|examples/|tests/)" + exclude: "^(docs/|examples/|tests/|setup.py$)" - id: pylint name: pylint (example code) description: Run pylint rules on "examples/*.py" files @@ -29,3 +32,10 @@ repos: files: "^examples/" args: - --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code + - id: pylint + name: pylint (test code) + description: Run pylint rules on "tests/*.py" files + types: [python] + files: "^tests/" + args: + - --disable=missing-docstring,consider-using-f-string,duplicate-code diff --git a/.pylintrc b/.pylintrc index 4408bdc..f6bdfea 100644 --- a/.pylintrc +++ b/.pylintrc @@ -14,7 +14,7 @@ unsafe-load-any-extension=no [MESSAGES CONTROL] confidence= -disable=raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,import-error,pointless-string-statement,unspecified-encoding,protected-access,unnecessary-list-index-lookup,duplicate-code +disable=raw-checker-failed,bad-inline-option,locally-disabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,import-error,pointless-string-statement,unspecified-encoding,protected-access,unnecessary-list-index-lookup,duplicate-code,import-outside-toplevel,attribute-defined-outside-init, too-many-positional-arguments enable= [REPORTS] @@ -110,12 +110,12 @@ valid-metaclass-classmethod-first-arg=mcs max-args=15 max-attributes=30 max-bool-expr=5 -max-branches=20 +max-branches=25 max-locals=25 max-parents=7 max-public-methods=20 max-returns=6 -max-statements=60 +max-statements=70 min-public-methods=0 [EXCEPTIONS] diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 19d9be3..3cdb96e 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -5,7 +5,7 @@ version: 2 build: - os: ubuntu-22.04 + os: ubuntu-lts-latest tools: python: "3" diff --git a/README.rst b/README.rst index 5a519ba..326a4ba 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,3 @@ -.. image:: https://readthedocs.org/projects/circuitpython-uplot/badge/?version=latest - :target: https://circuitpython-uplot.readthedocs.io/ - :alt: Documentation Status - .. image:: https://github.com/jposada202020/CircuitPython_uplot/workflows/Build%20CI/badge.svg :target: https://github.com/jposada202020/CircuitPython_uplot/actions :alt: Build Status @@ -14,10 +10,6 @@ :alt: Total PyPI downloads :target: https://pepy.tech/project/circuitpython-uplot -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code Style: Black - Framework to display different graphical plots in displayio. Take a look in the `examples `_ section in RTD to see the gallery @@ -27,8 +19,11 @@ For detailed view of the library please refer to the `Quick start guide `_. Thanks to @Casainho +Below a picture of a real live application. for more information visit the project `page `_. Thanks to @Casainho .. image:: https://github.com/jposada202020/CircuitPython_uplot/blob/main/docs/logging.png diff --git a/circuitpython_uplot/cartesian.py b/circuitpython_uplot/cartesian.py index 6ec7c33..fda8da6 100644 --- a/circuitpython_uplot/cartesian.py +++ b/circuitpython_uplot/cartesian.py @@ -39,6 +39,9 @@ def __init__( rangex: Optional[list] = None, rangey: Optional[list] = None, line_color: Optional[int] = None, + line_style: Optional[str] = None, + ticksx: Union[np.array, list] = None, + ticksy: Union[np.array, list] = None, fill: bool = False, nudge: bool = True, logging: bool = False, @@ -51,44 +54,61 @@ def __init__( :param list|None rangex: x range limits. Defaults to None :param list|None rangey: y range limits. Defaults to None :param int|None line_color: line color. Defaults to None + :param str|None line_style: line style. Defaults to None + :param np.array|list ticksx: X axis ticks values + :param np.array|list ticksy: Y axis ticks values :param bool fill: Show the filling. Defaults to `False` :param bool nudge: moves the graph a little for better displaying. Defaults to `True` :param bool logging: used to change the logic of the cartesian to work as a logger """ self.points = [] + self.ticksx = ticksx + self.ticksy = ticksy if line_color is not None: plot._plot_palette[plot._index_colorused] = line_color + if line_style is None: + self._line_type = "-" + else: + self._line_type = line_style + + if self._line_type not in ["-", ".", "- -", "-.-"]: + raise ValueError("line_style must be a valid option") + + if line_style is None: + self._line_type = "-" + if nudge: nudge_factor = 1 else: nudge_factor = 0 if rangex is None: - xmin = np.min(x) - nudge_factor * (abs(np.max(x) - np.min(x)) / 10) - xmax = np.max(x) + nudge_factor * (abs(np.max(x) - np.min(x)) / 10) + self.xmin = np.min(x) - nudge_factor * (abs(np.max(x) - np.min(x)) / 10) + self.xmax = np.max(x) + nudge_factor * (abs(np.max(x) - np.min(x)) / 10) + else: - xmin = min(rangex) - xmax = max(rangex) + self.xmin = min(rangex) + self.xmax = max(rangex) if rangey is None: - ymin = np.min(y) - nudge_factor * (abs(np.max(y) - np.min(y)) / 10) - ymax = np.max(y) + nudge_factor * (abs(np.max(y) - np.min(y)) / 10) + self.ymin = np.min(y) - nudge_factor * (abs(np.max(y) - np.min(y)) / 10) + self.ymax = np.max(y) + nudge_factor * (abs(np.max(y) - np.min(y)) / 10) else: - ymin = min(rangey) - ymax = max(rangey) + self.ymin = min(rangey) + self.ymax = max(rangey) x = np.array(x) y = np.array(y) xnorm = np.array( - plot.transform(xmin, xmax, plot._newxmin, plot._newxmax, x), + plot.transform(self.xmin, self.xmax, plot._newxmin, plot._newxmax, x), dtype=np.int16, ) ynorm = np.array( - plot.transform(ymin, ymax, plot._newymin, plot._newymax, y), + plot.transform(self.ymin, self.ymax, plot._newymin, plot._newymax, y), dtype=np.int16, ) @@ -121,22 +141,17 @@ def __init__( for index, _ in enumerate(xnorm): if index + 1 >= len(xnorm): break - if y[index] >= ymax: + if y[index] >= self.ymax: continue - draw_line( - plot._plotbitmap, - xnorm[index], - ynorm[index], - xnorm[index + 1], - ynorm[index + 1], - plot._index_colorused, - ) + + self._draw_plotline(plot, index, xnorm, ynorm) + if plot._showticks: if plot._cartesianfirst: if logging: - x = np.linspace(xmin, xmax, 100) - y = np.linspace(ymin, ymax, 100) - plot._draw_ticks(x, y) + x = np.linspace(self.xmin, self.xmax, 100) + y = np.linspace(self.ymin, self.ymax, 100) + plot._draw_ticks(x, y, self.ticksx, self.ticksy) plot._cartesianfirst = False plot._showticks = False @@ -144,3 +159,39 @@ def __init__( plot._index_colorused = plot._index_colorused else: plot._index_colorused = plot._index_colorused + 1 + + def _draw_plotline(self, plot, index, xnorm, ynorm): + if self._line_type == "-": + self._plot_line(plot, index, xnorm, ynorm) + elif self._line_type == "-.-": + if index % 3 == 0: + self._plot_line(plot, index, xnorm, ynorm) + else: + plot._plotbitmap[xnorm[index], ynorm[index]] = plot._index_colorused + elif self._line_type == ".": + plot._plotbitmap[xnorm[index], ynorm[index]] = plot._index_colorused + elif self._line_type == "- -": + if index % 2 == 0: + self._plot_line(plot, index, xnorm, ynorm) + + @staticmethod + def _plot_line(plot, index, xnorm, ynorm): + draw_line( + plot._plotbitmap, + xnorm[index], + ynorm[index], + xnorm[index + 1], + ynorm[index + 1], + plot._index_colorused, + ) + + +class LineStyle: + """ + Line style class + """ + + SOLID = "-" + DASHED = "- -" + DASH_DOT = "-.-" + DOTTED = "." diff --git a/circuitpython_uplot/logging.py b/circuitpython_uplot/logging.py index 6cc081e..c60c120 100644 --- a/circuitpython_uplot/logging.py +++ b/circuitpython_uplot/logging.py @@ -9,12 +9,12 @@ CircuitPython logging data graph -* Author(s): Jose D. Montoya +* Author: Jose D. Montoya """ try: - from typing import Union + from typing import Union, Optional from circuitpython_uplot.plot import Plot except ImportError: pass @@ -42,6 +42,8 @@ def __init__( ticksy: Union[np.array, list] = np.array([0, 10, 30, 50, 70, 90]), tick_pos: bool = False, fill: bool = False, + limits: Optional[list] = None, + limits_color: int = 0xFF0000, ) -> None: """ @@ -61,6 +63,7 @@ def __init__( self.points = [] self.ticksx = np.array(ticksx) self.ticksy = np.array(ticksy) + self._fill = fill if tick_pos: self._tickposx = plot._tickheightx self._tickposy = plot._tickheighty @@ -70,18 +73,29 @@ def __init__( plot._plot_palette[plot._index_colorused] = line_color + self._line_index = plot._index_colorused + self.xmin = rangex[0] self.xmax = rangex[1] self.ymin = rangey[0] self.ymax = rangey[1] - self.draw_points(plot, x, y, fill) + if limits is not None: + self._limits = np.array( + plot.transform( + self.ymin, + self.ymax, + plot._newymin, + plot._newymax, + np.array(limits), + ), + dtype=np.int16, + ) + plot._plot_palette[9] = limits_color + else: + self._limits = None - if plot._showticks: - if plot._loggingfirst: - self._draw_ticks(plot) - plot._loggingfirst = False - plot._showticks = False + self.draw_points(plot, x, y) def _draw_ticks(self, plot) -> None: """ @@ -89,20 +103,20 @@ def _draw_ticks(self, plot) -> None: """ - ticksxnorm = np.array( + self._ticksxnorm = np.array( plot.transform( self.xmin, self.xmax, plot._newxmin, plot._newxmax, self.ticksx ), dtype=np.int16, ) - ticksynorm = np.array( + self._ticksynorm = np.array( plot.transform( self.ymin, self.ymax, plot._newymin, plot._newymax, self.ticksy ), dtype=np.int16, ) - for i, tick in enumerate(ticksxnorm): + for i, tick in enumerate(self._ticksxnorm): draw_line( plot._plotbitmap, tick, @@ -113,7 +127,7 @@ def _draw_ticks(self, plot) -> None: ) if plot._showtext: plot.show_text(f"{self.ticksx[i]:.0f}", tick, plot._newymin, (0.5, 0.0)) - for i, tick in enumerate(ticksynorm): + for i, tick in enumerate(self._ticksynorm): draw_line( plot._plotbitmap, plot._newxmin - self._tickposy, @@ -140,7 +154,7 @@ def clear_plot(plot) -> None: 0, ) - def draw_points(self, plot: Plot, x: list, y: list, fill: bool = False) -> None: + def draw_points(self, plot: Plot, x: list, y: list) -> None: """ Draws points in the plot :param Plot plot: plot object provided @@ -149,11 +163,22 @@ def draw_points(self, plot: Plot, x: list, y: list, fill: bool = False) -> None: :param bool fill: parameter to fill the plot graphic. Defaults to False :return: None """ + self.clear_plot(plot) + if self._limits: + self._draw_limit_lines(plot) + self.draw_new_lines(plot, x, y) + if plot._showticks: + if plot._loggingfirst: + self._draw_ticks(plot) + plot._loggingfirst = False + plot._showticks = False - self.draw_new_lines(plot, x, y, fill) + if plot._tickgrid: + plot._draw_gridx(self._ticksxnorm) + plot._draw_gridy(self._ticksynorm) - def draw_new_lines(self, plot: Plot, x: list, y: list, fill: bool = False) -> None: + def draw_new_lines(self, plot: Plot, x: list, y: list) -> None: """ Draw the plot lines :param Plot plot: plot object provided @@ -186,9 +211,10 @@ def draw_new_lines(self, plot: Plot, x: list, y: list, fill: bool = False) -> No ynorm[index], xnorm[index + 1], ynorm[index + 1], - plot._index_colorused, + self._line_index, ) - if fill: + + if self._fill: for index, _ in enumerate(xnorm): draw_line( plot._plotbitmap, @@ -196,5 +222,23 @@ def draw_new_lines(self, plot: Plot, x: list, y: list, fill: bool = False) -> No ynorm[index], xnorm[index], plot._newymin, - plot._index_colorused, + self._line_index, ) + + def _draw_limit_lines(self, plot: Plot) -> None: + draw_line( + plot._plotbitmap, + plot._newxmin + 1, + self._limits[0], + plot._newxmax - 1, + self._limits[0], + 9, + ) + draw_line( + plot._plotbitmap, + plot._newxmin + 1, + self._limits[1], + plot._newxmax - 1, + self._limits[1], + 9, + ) diff --git a/circuitpython_uplot/plot.py b/circuitpython_uplot/plot.py index 1ef9705..7a63109 100644 --- a/circuitpython_uplot/plot.py +++ b/circuitpython_uplot/plot.py @@ -21,12 +21,8 @@ """ -# pylint: disable=too-many-statements, unused-import, no-member -# pylint: disable=unused-import, import-outside-toplevel, undefined-variable -# pylint: disable=attribute-defined-outside-init - try: - from typing import Union, Tuple + from typing import Union, Tuple, Optional from typing_extensions import Literal except ImportError: pass @@ -82,13 +78,13 @@ def __init__( height = 100 if x + width > 481: print( - "Modify this settings. Some of the graphics will not shown int the screen" + "Modify this setting. Some of the graphics will not shown int the screen" ) print("Defaulting to x=0") x = 0 if y + height > 321: print( - "Modify this settings. Some of the graphics will not shown int the screen" + "Modify this setting. Some of the graphics will not shown int the screen" ) print("Defaulting to y=0") y = 0 @@ -96,6 +92,7 @@ def __init__( super().__init__(x=x, y=y, scale=scale) self._axesparams = "box" + self._decimal_points = None self._width = width self._height = height @@ -109,6 +106,7 @@ def __init__( self._cartesianfirst = True self._loggingfirst = True + self._scatterfirst = True self._showtext = False @@ -127,7 +125,7 @@ def __init__( self._index_colorused = 4 - self._plotbitmap = displayio.Bitmap(width, height, 20) + self._plotbitmap = displayio.Bitmap(width, height, 10) if show_box: self._drawbox() @@ -164,12 +162,13 @@ def axs_params(self, axstype: Literal["box", "cartesian", "line"] = "box") -> No """ Setting up axs visibility - :param axstype: argument with the kind of axs you selected + :param str axstype: argument with the kind of axs you selected :return: None """ self._axesparams = axstype + self._update_plot() def _drawbox(self) -> None: """ @@ -178,6 +177,7 @@ def _drawbox(self) -> None: :return: None """ + self._plotbitmap.fill(0) if self._axesparams == "cartesian": draw_box = [True, True, False, False] @@ -230,7 +230,8 @@ def _drawbox(self) -> None: def draw_circle(self, radius: int = 5, x: int = 100, y: int = 100) -> None: """ - Draw a circle in the plot area + Draw a circle in the plot area. This function is kept here for + historical reasons. Please use :meth:`scatter` instead. :param int radius: circle radius :param int x: circles center x coordinate position in pixels, Defaults to 100. @@ -269,24 +270,41 @@ def transform( / (oldrangemax - oldrangemin) ) + newrangemin - def _draw_ticks(self, x: int, y: int) -> None: + def _draw_ticks(self, x: int, y: int, ticksx=None, ticksy=None) -> None: """ Draw ticks in the plot area :param int x: x coord :param int y: y coord + :param list[int] ticksx: x ticks data. Defaults to None + :param list[int] ticksy: y ticks data. Defaults to None :return:None """ - ticks = np.array([10, 30, 50, 70, 90]) - subticks = np.array([20, 40, 60, 80]) - ticksxnorm = np.array(self.transform(0, 100, np.min(x), np.max(x), ticks)) - ticksynorm = np.array(self.transform(0, 100, np.min(y), np.max(y), ticks)) + ticks_dummy = np.array([10, 30, 50, 70, 90]) + subticks_dummy = np.array([20, 40, 60, 80]) + + if ticksx is None: + ticksxnorm = np.array( + self.transform(0, 100, np.min(x), np.max(x), ticks_dummy) + ) + subticksxnorm = np.array( + self.transform(0, 100, np.min(x), np.max(x), subticks_dummy) + ) + else: + ticksxnorm = np.array(ticksx) - subticksxnorm = np.array(self.transform(0, 100, np.min(x), np.max(x), subticks)) - subticksynorm = np.array(self.transform(0, 100, np.min(y), np.max(y), subticks)) + if ticksy is None: + ticksynorm = np.array( + self.transform(0, 100, np.min(y), np.max(y), ticks_dummy) + ) + subticksynorm = np.array( + self.transform(0, 100, np.min(y), np.max(y), subticks_dummy) + ) + else: + ticksynorm = np.array(ticksy) ticksxrenorm = np.array( self.transform( @@ -294,24 +312,27 @@ def _draw_ticks(self, x: int, y: int) -> None: ), dtype=np.int16, ) + ticksyrenorm = np.array( self.transform( np.min(y), np.max(y), self._newymin, self._newymax, ticksynorm ), dtype=np.int16, ) - subticksxrenorm = np.array( - self.transform( - np.min(x), np.max(x), self._newxmin, self._newxmax, subticksxnorm - ), - dtype=np.int16, - ) - subticksyrenorm = np.array( - self.transform( - np.min(y), np.max(y), self._newymin, self._newymax, subticksynorm - ), - dtype=np.int16, - ) + if ticksx is None: + subticksxrenorm = np.array( + self.transform( + np.min(x), np.max(x), self._newxmin, self._newxmax, subticksxnorm + ), + dtype=np.int16, + ) + if ticksy is None: + subticksyrenorm = np.array( + self.transform( + np.min(y), np.max(y), self._newymin, self._newymax, subticksynorm + ), + dtype=np.int16, + ) for i, tick in enumerate(ticksxrenorm): draw_line( self._plotbitmap, @@ -323,7 +344,10 @@ def _draw_ticks(self, x: int, y: int) -> None: ) if self._showtext: self.show_text( - "{:.2f}".format(ticksxnorm[i]), tick, self._newymin, (0.5, 0.0) + "{:.{}f}".format(ticksxnorm[i], self._decimal_points), + tick, + self._newymin + 5, + (0.5, 0.0), ) for i, tick in enumerate(ticksyrenorm): draw_line( @@ -336,26 +360,33 @@ def _draw_ticks(self, x: int, y: int) -> None: ) if self._showtext: self.show_text( - "{:.2f}".format(ticksynorm[i]), self._newxmin, tick, (1.0, 0.5) + "{:.{}f}".format(ticksynorm[i], self._decimal_points), + self._newxmin - 5, + tick, + (1.0, 0.5), + ) + + if ticksx is None: + for tick in subticksxrenorm: + draw_line( + self._plotbitmap, + tick, + self._newymin, + tick, + self._newymin - self._tickheightx // 2, + 2, + ) + + if ticksy is None: + for tick in subticksyrenorm: + draw_line( + self._plotbitmap, + self._newxmin, + tick, + self._newxmin + self._tickheighty // 2, + tick, + 2, ) - for tick in subticksxrenorm: - draw_line( - self._plotbitmap, - tick, - self._newymin, - tick, - self._newymin - self._tickheightx // 2, - 2, - ) - for tick in subticksyrenorm: - draw_line( - self._plotbitmap, - self._newxmin, - tick, - self._newxmin + self._tickheighty // 2, - tick, - 2, - ) if self._tickgrid: self._draw_gridx(ticksxrenorm) @@ -369,19 +400,26 @@ def tick_params( tickcolor: int = 0xFFFFFF, tickgrid: bool = False, showtext: bool = False, + decimal_points: int = 0, ) -> None: """ Function to set ticks parameters + :param bool show_ticks: Show ticks. Defaults to `True` :param int tickx_height: X axes tick height in pixels. Defaults to 8 :param int ticky_height: Y axes tick height in pixels. Defaults to 8 :param int tickcolor: tick color in hex. Defaults to white. ``0xFFFFFF`` :param bool tickgrid: defines if the grid is to be shown. Defaults to `False` :param bool showtext: Show Axes text. Defaults to `False` + :param int decimal_points: Number of decimal points to show. Defaults to :const:`0` :return: None """ + if showtext and self.padding < 20: + raise ValueError( + "Please select a padding that allows to show the tick text" + ) self._showticks = show_ticks self._tickheightx = tickx_height @@ -389,6 +427,7 @@ def tick_params( self._plot_palette[2] = tickcolor self._tickgrid = tickgrid self._showtext = showtext + self._decimal_points = decimal_points if self._showtext: from adafruit_display_text import bitmap_label @@ -438,7 +477,7 @@ def _draw_gridy(self, ticks_data: list[int]) -> None: ) start = start + self._grid_espace + self._grid_lenght - def update_plot(self) -> None: + def _update_plot(self) -> None: """ Function to update graph @@ -449,7 +488,14 @@ def update_plot(self) -> None: self._drawbox() def show_text( - self, text: str, x: int, y: int, anchorpoint: Tuple = (0.5, 0.0) + self, + text: str, + x: int, + y: int, + anchorpoint: Tuple = (0.5, 0.0), + text_color: Optional[int] = None, + free_text: bool = False, + font=None, ) -> None: """ @@ -458,17 +504,38 @@ def show_text( :param int x: x coordinate :param int y: y coordinate :param Tuple anchorpoint: Display_text anchor point. Defaults to (0.5, 0.0) + :param int color: text color. Defaults to None + :param bool free_text: Select to show free text + :param font: font to be used. Defaults to None :return: None """ - if self._showtext: - text_toplot = self.bitmap_label.Label(terminalio.FONT, text=text, x=x, y=y) + if font is None: + font = terminalio.FONT + try: + self.bitmap_label + except AttributeError: + from adafruit_display_text import bitmap_label + + self.bitmap_label = bitmap_label + + if text_color is None: + text_color = self._plot_palette[2] + + if self._showtext or free_text: + text_toplot = self.bitmap_label.Label( + font, text=text, x=x, y=y, color=text_color + ) text_toplot.anchor_point = anchorpoint text_toplot.anchored_position = (x, y) self.append(text_toplot) -# pylint: disable=missing-class-docstring, too-few-public-methods, invalid-name +# pylint: disable=too-few-public-methods, invalid-name class color: + """ + Class to define colors in HEX + """ + WHITE = 0xFFFFFF BLACK = 0x000000 RED = 0xFF0000 @@ -479,3 +546,10 @@ class color: ORANGE = 0xFF9933 TEAL = 0x158FAD GRAY = 0x808080 + PINK = 0xFF40C0 + LIGHT_GRAY = 0xAAAAAA + BROWN = 0xCA801D + DARK_GREEN = 0x008700 + TURQUOISE = 0x00C0C0 + DARK_BLUE = 0x0000AA + DARK_RED = 0x800000 diff --git a/circuitpython_uplot/scatter.py b/circuitpython_uplot/scatter.py index d8e21df..220d755 100644 --- a/circuitpython_uplot/scatter.py +++ b/circuitpython_uplot/scatter.py @@ -23,12 +23,17 @@ from ulab import numpy as np import displayio -from vectorio import Circle +from vectorio import Circle, Polygon __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/CircuitPython_uplot.git" +_TRIANGLE = [(0, 0), (8, 0), (4, -7)] +_SQUARE = [(0, 0), (6, 0), (6, -6), (0, -6)] +_DIAMOND = [(0, 0), (3, -4), (6, 0), (3, 4)] + + class Scatter: """ Main class to display different graphics @@ -42,7 +47,8 @@ def __init__( rangex: Optional[list] = None, rangey: Optional[list] = None, radius: Optional[Union[list, int]] = 3, - circle_color: int = 0xFF905D, + pointer_color: int = 0xFF905D, + pointer: Optional[str] = None, nudge: bool = True, ) -> None: """ @@ -53,6 +59,8 @@ def __init__( :param list|None rangex: x range limits :param list|None rangey: y range limits :param int|list radius: circle radius + :param int pointer_color: pointer color. Default is 0xFF905D + :param str|None pointer: pointer shape. :param bool nudge: moves the graph a little for better displaying """ @@ -61,6 +69,19 @@ def __init__( else: nudge_factor = 0 + if pointer is None: + self._pointer = "circle" + else: + self._pointer = pointer + + self._radius = radius + self._pointer_color = pointer_color + + if isinstance(self._radius, list) and self._pointer != "circle": + raise ValueError( + f"Pointer paramater is {self._pointer}. Variable Radius are not accepted" + ) + if rangex is None: xmin = np.min(x) - nudge_factor * (abs(np.max(x) - np.min(x)) / 10) xmax = np.max(x) + nudge_factor * (abs(np.max(x) - np.min(x)) / 10) @@ -78,30 +99,88 @@ def __init__( x = np.array(x) y = np.array(y) - xnorm = np.array( + self._xnorm = np.array( plot.transform(xmin, xmax, plot._newxmin, plot._newxmax, x), dtype=np.int16, ) - ynorm = np.array( + self._ynorm = np.array( plot.transform(ymin, ymax, plot._newymin, plot._newymax, y), dtype=np.int16, ) - palette = displayio.Palette(1) - palette[0] = circle_color + self._draw_pointer(plot) + + if plot._scatterfirst: + if plot._showticks: + plot._draw_ticks(x, y) + + plot._scatterfirst = False + plot._showticks = False + + def _draw_pointer(self, plot: Plot) -> None: + """ + + :param plot: Plot object for the scatter to be drawn - if isinstance(radius, list): - for i, _ in enumerate(x): + """ + palette = displayio.Palette(1) + palette[0] = self._pointer_color + if isinstance(self._radius, list): + for i, _ in enumerate(self._xnorm): plot.append( Circle( - pixel_shader=palette, radius=radius[i], x=xnorm[i], y=ynorm[i] + pixel_shader=palette, + radius=self._radius[i], + x=self._xnorm[i], + y=self._ynorm[i], ) ) else: - for i, _ in enumerate(x): - plot.append( - Circle(pixel_shader=palette, radius=radius, x=xnorm[i], y=ynorm[i]) - ) + for i, _ in enumerate(self._xnorm): + if self._pointer == "circle": + plot.append( + Circle( + pixel_shader=palette, + radius=self._radius, + x=self._xnorm[i], + y=self._ynorm[i], + ) + ) + elif self._pointer == "triangle": + plot.append( + Polygon( + points=_TRIANGLE, + pixel_shader=palette, + x=self._xnorm[i], + y=self._ynorm[i], + ) + ) + elif self._pointer == "square": + plot.append( + Polygon( + points=_SQUARE, + pixel_shader=palette, + x=self._xnorm[i], + y=self._ynorm[i], + ) + ) + elif self._pointer == "diamond": + plot.append( + Polygon( + points=_DIAMOND, + pixel_shader=palette, + x=self._xnorm[i], + y=self._ynorm[i], + ) + ) + + +class Pointer: + """ + Pointer container class + """ - if plot._showticks: - plot._draw_ticks(x, y) + CIRCLE = "circle" + TRIANGLE = "triangle" + SQUARE = "square" + DIAMOND = "diamond" diff --git a/circuitpython_uplot/shade.py b/circuitpython_uplot/shade.py index de6ebb8..4e7aca3 100644 --- a/circuitpython_uplot/shade.py +++ b/circuitpython_uplot/shade.py @@ -7,7 +7,7 @@ `shade` ================================================================================ -CircuitPython shade utility for uPlot. +CircuitPython shade utility for Plotting. * Author(s): Jose D. Montoya @@ -100,7 +100,7 @@ def __init__( plot._plotbitmap, min(xnorm), min(y1norm), - max(xnorm), + max(xnorm) + 1, max(y2norm), plot._index_colorused, ) diff --git a/circuitpython_uplot/svg.py b/circuitpython_uplot/svg.py index b73f203..a4b4a28 100644 --- a/circuitpython_uplot/svg.py +++ b/circuitpython_uplot/svg.py @@ -24,8 +24,6 @@ __repo__ = "https://github.com/adafruit/CircuitPython_uplot.git" -# pylint: disable=too-many-arguments, invalid-name, no-self-use, too-few-public-methods -# pylint: disable=too-many-locals, too-many-branches, protected-access, unnecessary-list-index-lookup class SVG: """ class to render svg images in the plot area diff --git a/docs/uplot_3DBars.jpg b/docs/3DBars.jpg similarity index 100% rename from docs/uplot_3DBars.jpg rename to docs/3DBars.jpg diff --git a/docs/api.rst b/docs/api.rst index 5694701..b16d5d0 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,5 +1,5 @@ -Uplot Library -============== +Microplot Library +====================== .. automodule:: circuitpython_uplot.plot :members: diff --git a/docs/boxes_types.png b/docs/boxes_types.png new file mode 100644 index 0000000..73e5e66 Binary files /dev/null and b/docs/boxes_types.png differ diff --git a/docs/uplot_cartesian_advance.jpg b/docs/cartesian_advance.jpg similarity index 100% rename from docs/uplot_cartesian_advance.jpg rename to docs/cartesian_advance.jpg diff --git a/docs/cartesian_fill.jpg b/docs/cartesian_fill.jpg new file mode 100644 index 0000000..787e698 Binary files /dev/null and b/docs/cartesian_fill.jpg differ diff --git a/docs/uplot_cartesian.gif b/docs/cartesian_logging_data.gif similarity index 100% rename from docs/uplot_cartesian.gif rename to docs/cartesian_logging_data.gif diff --git a/docs/cartesian_scatter_polyfit.jpg b/docs/cartesian_scatter_polyfit.jpg new file mode 100644 index 0000000..30cdfe4 Binary files /dev/null and b/docs/cartesian_scatter_polyfit.jpg differ diff --git a/docs/colors.png b/docs/colors.png new file mode 100644 index 0000000..d8e9a0a Binary files /dev/null and b/docs/colors.png differ diff --git a/docs/conf.py b/docs/conf.py index 9c7c2b2..c5bcb16 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -42,7 +42,7 @@ source_suffix = ".rst" master_doc = "index" # General information about the project. -project = "CircuitPython uplot Library" +project = "CircuitPython microplot Library" creation_year = "2023" current_year = str(datetime.datetime.now().year) year_duration = ( @@ -89,17 +89,10 @@ # on_rtd = os.environ.get("READTHEDOCS", None) == "True" -if not on_rtd: # only import and set the theme if we're building docs locally - try: - import sphinx_rtd_theme - - html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] - except: - html_theme = "default" - html_theme_path = ["."] -else: - html_theme_path = ["."] +import sphinx_rtd_theme + +html_theme = "sphinx_rtd_theme" +html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] # 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, diff --git a/docs/uplot_ex6.jpg b/docs/display_shapes.jpg similarity index 100% rename from docs/uplot_ex6.jpg rename to docs/display_shapes.jpg diff --git a/docs/examples.rst b/docs/examples.rst index 9c06ddc..b67ce1b 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -1,3 +1,7 @@ +================= +Plot Examples +================= + Simple test ------------ @@ -14,141 +18,128 @@ Plot Example Plot some data for x and y -.. literalinclude:: ../examples/uplot_plot_example.py - :caption: examples/uplot_plot_example.py +.. literalinclude:: ../examples/plot_example.py + :caption: examples/plot_example.py :lines: 5- -.. image:: ../docs/uplot_ex4.jpg +.. image:: ../docs/plot_example.jpg Tick Parameters Settings Example ---------------------------------- Setting up the ticks parameters -.. literalinclude:: ../examples/uplot_tickparameters.py - :caption: examples/uplot_tickparameters.py +.. literalinclude:: ../examples/tickparameters.py + :caption: examples/tickparameters.py :lines: 5- -.. image:: ../docs/uplot_ex3.jpg +.. image:: ../docs/tickparameters.jpg Integration Example ------------------- Example showing different graphics elements integration -.. literalinclude:: ../examples/uplot_integration_example.py - :caption: examples/uplot_integration_example.py +.. literalinclude:: ../examples/integration_example.py + :caption: examples/integration_example.py :lines: 5- -.. image:: ../docs/uplot_ex5.jpg +.. image:: ../docs/integration_example.jpg + +================== +Scatter examples +================== Scatter Example ------------------- Scatter plot Example -.. literalinclude:: ../examples/uplot_scatter.py - :caption: examples/uplot_scatter.py +.. literalinclude:: ../examples/scatter.py + :caption: examples/scatter.py :lines: 5- .. image:: ../docs/scatter.jpg -Display_shapes Example ------------------------ +Scatter Circle Pointers with diferent Radius +--------------------------------------------- -Display Shapes integration example +Example showing how to use different radius in the circle pointers -.. literalinclude:: ../examples/uplot_display_shapes.py - :caption: examples/uplot_display_shapes.py +.. literalinclude:: ../examples/scatter_circle_radius.py + :caption: examples/scatter_circle_radius.py :lines: 5- -.. image:: ../docs/uplot_ex6.jpg - -Bar Example ----------------- - -Bar example +.. image:: ../docs/scatter_circle_radius.jpg -.. literalinclude:: ../examples/uplot_bar_example.py - :caption: examples/uplot_bar_example.py - :lines: 5- -.. image:: ../docs/bar_example.jpg - -Bar Scale Example ---------------------- - -Bar plot example showing how to use the scale - -.. literalinclude:: ../examples/uplot_bar_scale_example.py - :caption: examples/uplot_bar_scale_example.py - :lines: 5- -.. image:: ../docs/bar_scale.jpg - - -Bar Color Palette Example +Scatter Pointers Example ---------------------------- -Bar plot example showing how to pass a user color Palette +Example showing how to use different pointers -.. literalinclude:: ../examples/uplot_bar_colorpalette.py - :caption: examples/uplot_bar_colorpalette.py +.. literalinclude:: ../examples/scatter.py + :caption: examples/scatter.py :lines: 5- -.. image:: ../docs/bar_palette.jpg +.. image:: ../docs/scatter_pointers.jpg +Scatter using different datasets +---------------------------------- -Bar plot updating values Example ---------------------------------- +Example showing how to use different datasets -Bar Plot example showing how to update values for a filled bars bar plot - -.. literalinclude:: ../examples/uplot_bar_updating_values.py - :caption: examples/uplot_bar_updating_values.py +.. literalinclude:: ../examples/scatter_using_different_datasets.py + :caption: examples/scatter_using_different_datasets.py :lines: 5- +.. image:: ../docs/scatter_using_different_datasets.jpg -Bar plot updating bar colors Example -------------------------------------- +================== +Cartesian examples +================== -Bar Plot example showing how to update colors for a filled bars bar plot +Cartesian and Scatter Example +------------------------------ -.. literalinclude:: ../examples/uplot_bar_color_changing.py - :caption: examples/uplot_bar_color_changing.py - :lines: 5- +Example showing how to use cartesian and scatter in the same plot +.. literalinclude:: ../examples/cartersian_and_scatter_polyfit_example.py + :caption: examples/cartersian_and_scatter_polyfit_example.py + :lines: 5- +.. image:: ../docs/cartesian_scatter_polyfit.jpg -Bar 3D Example ----------------- +Plot Line Style Example +--------------------------- -Bar 3D example +Plot some data for x and y with different line styles -.. literalinclude:: ../examples/uplot_bar_3Dbars.py - :caption: examples/uplot_bar_3Dbars.py +.. literalinclude:: ../examples/plot_line_styles.py + :caption: examples/plot_line_styles.py :lines: 5- -.. image:: ../docs/uplot_3DBars.jpg +.. image:: ../docs/line_style.jpg -Pie Example ----------------- +Cartesian fill Example +--------------------------- -Pie example +Cartesian fill example -.. literalinclude:: ../examples/uplot_pie_example.py - :caption: examples/uplot_pie_example.py +.. literalinclude:: ../examples/cartesian_fill.py + :caption: examples/cartesian_fill.py :lines: 5- -.. image:: ../docs/uplot_pie.jpg +.. image:: ../docs/cartesian_fill.jpg Cartesian Advanced Example --------------------------- Showing the ability to display to graphs in the same plot with different colors -.. literalinclude:: ../examples/uplot_cartesian_advanced.py - :caption: examples/uplot_cartesian_advanced.py +.. literalinclude:: ../examples/cartesian_advanced.py + :caption: examples/cartesian_advanced.py :lines: 5- -.. image:: ../docs/uplot_cartesian_advance.jpg +.. image:: ../docs/cartesian_advance.jpg Cartesian Table Example --------------------------- Example showing how to add a data table to the plot -.. literalinclude:: ../examples/uplot_cartesian_table.py - :caption: examples/uplot_cartesian_table.py +.. literalinclude:: ../examples/cartesian_table.py + :caption: examples/cartesian_table.py :lines: 5- Lissajous Curves Example @@ -166,8 +157,8 @@ Cartesian Polar Plots Example Example showing how to draw polar plots using Cartesian -.. literalinclude:: ../examples/uplot_polar_plots.py - :caption: examples/uplot_polar_plots.py +.. literalinclude:: ../examples/polar_plots.py + :caption: examples/polar_plots.py :lines: 5- .. image:: ../docs/polar_plots.jpg @@ -181,82 +172,172 @@ Example showing how to draw Trigonometrics plots using Cartesian :lines: 5- .. image:: ../docs/cartesian_trig_functions.jpg -Stackplot Example + +Cartesian Animation Example --------------------------- -Stackplot simple example +Cartesian animation example -.. literalinclude:: ../examples/uplot_stackplot.py - :caption: examples/uplot_stackplot.py - :lines: 8- -.. image:: ../docs/uplot_ex12.jpg +.. literalinclude:: ../examples/cartesian_logging_data.py + :caption: examples/cartesian_logging_data.py + :lines: 5- +.. image:: ../docs/cartesian_logging_data.gif -Advanced Example + +Cartesian Koch Snowflake --------------------------- -plot different ulements in a single display +Cartesian koch snowflake example -.. literalinclude:: ../examples/uplot_readme_example.py - :caption: examples/uplot_readme_example.py +.. literalinclude:: ../examples/cartesian_koch.py + :caption: examples/cartesian_koch.py :lines: 5- -.. image:: ../docs/readme.png +.. image:: ../docs/koch.jpg -Fillbetween Example + +Cartesian Koch Curve --------------------------- -Example of fillbetween plot +Cartesian koch curve example -.. literalinclude:: ../examples/uplot_fillbetween.py - :caption: examples/uplot_fillbetween.py +.. literalinclude:: ../examples/cartesian_koch_2.py + :caption: examples/cartesian_koch_2.py :lines: 5- -.. image:: ../docs/fillbetween_example.jpg +.. image:: ../docs/koch2.jpg -Uboxplot Example ---------------------------- +================== +Bar Examples +================== -example of uboxplot integration with uplot +Bar Example +---------------- -.. literalinclude:: ../examples/uplot_uboxplot.py - :caption: examples/uplot_uboxplot.py - :lines: 8- -.. image:: ../docs/uplot_ex16.jpg +Bar example -Map Example ---------------------------- +.. literalinclude:: ../examples/bar_example.py + :caption: examples/bar_example.py + :lines: 5- +.. image:: ../docs/bar_example.jpg -map simple example +Bar Scale Example +--------------------- -.. literalinclude:: ../examples/uplot_map.py - :caption: examples/uplot_map.py +Bar plot example showing how to use the scale + +.. literalinclude:: ../examples/bar_scale_example.py + :caption: examples/bar_scale_example.py :lines: 5- -.. image:: ../docs/map.jpg +.. image:: ../docs/bar_scale.jpg -Sparkline Animation Example + +Bar Color Palette Example +---------------------------- + +Bar plot example showing how to pass a user color Palette + +.. literalinclude:: ../examples/bar_colorpalette.py + :caption: examples/bar_colorpalette.py + :lines: 5- +.. image:: ../docs/bar_palette.jpg + + +Bar plot updating values Example +--------------------------------- + +Bar Plot example showing how to update values for a filled bars bar plot + +.. literalinclude:: ../examples/bar_updating_values.py + :caption: examples/bar_updating_values.py + :lines: 5- + +Bar plot updating bar colors Example +------------------------------------- + +Bar Plot example showing how to update colors for a filled bars bar plot + +.. literalinclude:: ../examples/bar_color_changing.py + :caption: examples/bar_color_changing.py + :lines: 5- + + +Bar 3D Example +---------------- + +Bar 3D example + +.. literalinclude:: ../examples/bar_3Dbars.py + :caption: examples/bar_3Dbars.py + :lines: 5- +.. image:: ../docs/3DBars.jpg + +================ +Pie Examples +================ + +Pie Example +---------------- + +Pie example + +.. literalinclude:: ../examples/pie_example.py + :caption: examples/pie_example.py + :lines: 5- +.. image:: ../docs/pie.jpg + +=================== +Stackplot Examples +=================== + +Stackplot Example --------------------------- -Sparkline animation example +Stackplot simple example + +.. literalinclude:: ../examples/stackplot.py + :caption: examples/stackplot.py + :lines: 8- +.. image:: ../docs/stackplot_example.jpg + +==================== +Fillbetween Examples +==================== + +Fillbetween Example +--------------------------- + +Example of fillbetween plot -.. literalinclude:: ../examples/uplot_sparkline.py - :caption: examples/uplot_sparkline.py +.. literalinclude:: ../examples/fillbetween.py + :caption: examples/fillbetween.py :lines: 5- +.. image:: ../docs/fillbetween_example.jpg -Cartesian Animation Example +==================== +Map Examples +==================== + +Map Example --------------------------- -Cartesian animation example +map simple example -.. literalinclude:: ../examples/uplot_cartesian_loggin_data.py - :caption: examples/uplot_cartesian_loggin_data.py +.. literalinclude:: ../examples/map.py + :caption: examples/map.py :lines: 5- -.. image:: ../docs/uplot_cartesian.gif +.. image:: ../docs/map.jpg + + +==================== +Logging Examples +==================== Logging Example --------------------------- Logging example -.. literalinclude:: ../examples/uplot_logging.py - :caption: examples/uplot_logging.py +.. literalinclude:: ../examples/logging.py + :caption: examples/logging.py :lines: 5- Logging Fill Example @@ -264,8 +345,8 @@ Logging Fill Example Logging fill example -.. literalinclude:: ../examples/uplot_logging_fill.py - :caption: examples/uplot_logging_fill.py +.. literalinclude:: ../examples/logging_fill.py + :caption: examples/logging_fill.py :lines: 5- .. image:: ../docs/logging_fill.jpg @@ -275,8 +356,8 @@ Logging Changing Values Example This example shows how to redraw new_values in the same plot -.. literalinclude:: ../examples/uplot_logging_changing_values.py - :caption: examples/uplot_logging_changing_values.py +.. literalinclude:: ../examples/logging_changing_values.py + :caption: examples/logging_changing_values.py :lines: 5- Logging with Table Example @@ -284,8 +365,8 @@ Logging with Table Example This example shows how to add a data table to the plot -.. literalinclude:: ../examples/uplot_logging_table.py - :caption: examples/uplot_logging_table.py +.. literalinclude:: ../examples/logging_table.py + :caption: examples/logging_table.py :lines: 10- .. image:: ../docs/logging_table.jpg @@ -295,37 +376,70 @@ Logging Animation Example This example shows how to animate a plot -.. literalinclude:: ../examples/uplot_logging_animation.py - :caption: examples/uplot_logging_animation.py +.. literalinclude:: ../examples/logging_animation.py + :caption: examples/logging_animation.py + :lines: 5- + +Logging Animation Example +--------------------------------------- + +This example shows how to add limits to our plot + +.. literalinclude:: ../examples/logging_limits.py + :caption: examples/logging_limits.py + :lines: 5- +.. image:: ../docs/logging_limits.jpg + + +Logging with Dial Gauge Library +--------------------------------------- + +This example shows how to add limits to our plot + +.. literalinclude:: ../examples/logging_with_dial_gauge.py + :caption: examples/logging_with_dial_gauge.py :lines: 5- +.. image:: ../docs/logging_dial.jpg + +==================== +SVG Examples +==================== SVG Images examples --------------------------- SVG Images example -.. literalinclude:: ../examples/uplot_svg_example.py - :caption: examples/uplot_svg_example.py +.. literalinclude:: ../examples/svg_example.py + :caption: examples/svg_example.py :lines: 5- -.. image:: ../docs/uplot_svg.jpg +.. image:: ../docs/svg.jpg + +==================== +Shade Examples +==================== Shade examples --------------------------- Shade example -.. literalinclude:: ../examples/uplot_shade_example.py - :caption: examples/uplot_shade_example.py +.. literalinclude:: ../examples/shade_example.py + :caption: examples/shade_example.py :lines: 5- -.. image:: ../docs/uplot_shade.jpg +.. image:: ../docs/shade.jpg + +==================== +Polar Plot Examples +==================== Polar example --------------------------- Show how to use the Polar Plot -.. literalinclude:: ../examples/uplot_polar_example.py - :caption: examples/uplot_polar_example.py +.. literalinclude:: ../examples/polar_example.py + :caption: examples/polar_example.py :lines: 5- .. image:: ../docs/polar_example.jpg @@ -338,3 +452,45 @@ Polar Advanced example :caption: examples/polar_advanced.py :lines: 5- .. image:: ../docs/polar_advanced.jpg + +================== +Others +================== +Sparkline Animation Example +--------------------------- + +Sparkline animation example + +.. literalinclude:: ../examples/sparkline.py + :caption: examples/sparkline.py + :lines: 5- + +Display_shapes Example +----------------------- + +Display Shapes integration example + +.. literalinclude:: ../examples/display_shapes.py + :caption: examples/display_shapes.py + :lines: 5- +.. image:: ../docs/display_shapes.jpg + +Advanced Example +--------------------------- + +plot different elements in a single display + +.. literalinclude:: ../examples/readme_example.py + :caption: examples/readme_example.py + :lines: 5- +.. image:: ../docs/readme.png + +Uboxplot Example +--------------------------- + +example of uboxplot integration in a plot + +.. literalinclude:: ../examples/uboxplot_example.py + :caption: examples/uboxplot_example.py + :lines: 8- +.. image:: ../docs/uboxplot_example.jpg diff --git a/docs/grid_text.png b/docs/grid_text.png new file mode 100644 index 0000000..4ad9cd7 Binary files /dev/null and b/docs/grid_text.png differ diff --git a/docs/index.rst b/docs/index.rst index 8b4e797..c2bc3ca 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,17 +1,17 @@ :orphan: -.. title:: uplot documentation +.. title:: microplot documentation .. module:: uplot -################### -uplot documentation -################### +######################### +Microplot documentation +######################### Framework to display different plots in displayio. Similar to widget Take a look in the `examples `_ section in RTD to see the gallery -uplot is to be used with CircuitPython as some of the behind the curtains methods are +microplot is to be used with CircuitPython as some of the behind the curtains methods are in the CircuitPython core and could differ from MicroPython or Python diff --git a/docs/uplot_ex5.jpg b/docs/integration_example.jpg similarity index 100% rename from docs/uplot_ex5.jpg rename to docs/integration_example.jpg diff --git a/docs/koch.jpg b/docs/koch.jpg new file mode 100644 index 0000000..24bc8d8 Binary files /dev/null and b/docs/koch.jpg differ diff --git a/docs/koch2.jpg b/docs/koch2.jpg new file mode 100644 index 0000000..44f9390 Binary files /dev/null and b/docs/koch2.jpg differ diff --git a/docs/line_style.jpg b/docs/line_style.jpg new file mode 100644 index 0000000..46b68d3 Binary files /dev/null and b/docs/line_style.jpg differ diff --git a/docs/logging_dial.jpg b/docs/logging_dial.jpg new file mode 100644 index 0000000..b696816 Binary files /dev/null and b/docs/logging_dial.jpg differ diff --git a/docs/logging_limits.jpg b/docs/logging_limits.jpg new file mode 100644 index 0000000..436fec5 Binary files /dev/null and b/docs/logging_limits.jpg differ diff --git a/docs/uplot_pie.jpg b/docs/pie.jpg similarity index 100% rename from docs/uplot_pie.jpg rename to docs/pie.jpg diff --git a/docs/uplot_ex4.jpg b/docs/plot_example.jpg similarity index 100% rename from docs/uplot_ex4.jpg rename to docs/plot_example.jpg diff --git a/docs/quick_start.rst b/docs/quick_start.rst index cee931c..5d19461 100644 --- a/docs/quick_start.rst +++ b/docs/quick_start.rst @@ -1,52 +1,53 @@ -A small tour for uplot. +A small tour explaining microplot. Plot Usage ============= -We start importing some fundamental libraries for plot to operate +We start by importing some fundamental libraries for the plot library to operate + .. code-block:: python import board - import displayio from circuitpython_uplot.plot import Plot -For reference, screen in CircuitPython are defined from left to right and up to bottom. This means -that our (x=0, y=0) will be in the left upper corner of the screen. -For boards or feather with a integrated screen the following statement will initiate the scree +For reference, screens in CircuitPython are defined from left to right and top to bottom. This means +that our (x=0, y=0) coordinates would be in the left upper corner of the screen. +For boards or feathers with an integrated screen the following statement will initiate the screen .. code-block:: python display = board.DISPLAY -For other displays please consult the right support library +For other displays please consult their support library -We add the plot area. in this case we are selecting the whole screen as our plot area +After this, we are ready to add the plot area. The following code will create a plot area that will cover the whole screen. +However you can select any area of the screen. .. code-block:: python plot = Plot(0, 0, display.width, display.height) -The Plot will be used to display our graphics. The position and the size of the plot area +The plot object will be used to display our graphics. The position and the size of the plot area could vary. This allows us to have more than 1 plot at the same time in the screen. -Every one of them with different characteristics or graphs. +Each one of them can have different characteristics or graphs according to your needs. -Options available are: +Options available to customize the plot area are: * width: width of the plot area * height: height of the plot area - * backround_color: Allows to change the background color. The default is black. - * box_color: Allows to change the box color. Default is white. + * background_color: allows you to change the background color. The default is black. + * box_color: allows you to change the box color. This default is white. * padding: allows the user to give the plot area a pad. This is helpful if you are planning to include text and legends in the axes. - * scale: scale of the plot. This will allow a plot to be scaled up at a user defined rate. This is currently only available for logging and bar plots. + * scale: scale of the plot. This will allow a plot to be scaled up at a user defined rate. This is only available for logging and bar plots. -We tell the microcontroller to display our plot: +We then tell the microcontroller to display our plot: .. code-block:: python display.show(plot) -And that is it you know have a plot area to add amazing graphs! +And this is how to build a plot area to add amazing graphs! .. image:: ../docs/readme.png @@ -56,7 +57,7 @@ Good Luck! Graphics =========== -At the moment the following objects can be added to the plot area: +The following objects can be added to the plot area: * Elements in the library * Cartesian Plane @@ -65,12 +66,15 @@ At the moment the following objects can be added to the plot area: * Bar graph * Pie Chart * Colormap + * Polar graph + * SVG (Rudimentary support) + * Logging graph * Display_shapes library objects * Histograms from the uhistogram library * Boxplots from the uboxplot library * Individual Vectorio Objects -In a more advanced method it is possible to add directly to the plot area using the plot bitmap object +It is possible to add directly to the plot area using the plot bitmap object as shown below The following code shows an example adding a shape from the Adafruit_Display_shapes library @@ -95,9 +99,9 @@ Ticks and Grid Plot axes are shown by default. To change this behaviour you would need to use the correct keyword in the `Plot.axs_params` function: -.. py:function:: Plot.axs_params(axstype: Literal["box", "cartesian", "line"] = "box") +.. py:function:: Plot.axs_params(axstype = "box") - :param axstype: Option to display the axes + :param axstype: Option to display the axes. Defaults to "box" Options available are: * box : draws a box @@ -111,19 +115,29 @@ The following snippet shows how to create a cartesian plot plot = Plot(0, 0, display.width, display.height) plot.axs_params(axstype="cartesian") -Tick spacing and numbers are selected by default. However it's possible to customize -the following parameters: +.. image:: ../docs/boxes_types.png -.. py:function:: Plot.tick_params(tickx_height, ticky_height, tickcolor, tickgrid) +Tick spacing and numbers are selected and calculated by default. In Cartesian and Logging Plots you can select the ticks to +show in the plot. For other plots, it is possible to customize the following parameters: +.. py:function:: Plot.tick_params(showtick, tickx_height, ticky_height, tickcolor, tickgrid, showtext, decimal_points) + + :param bool showtick: displays the tick. Defaults to `True` :param int tickx_height: tickx_height in pixels :param int ticky_height: ticky_height in pixels :param int tickcolor: tickcolor in Hex format :param bool tickgrid: displays the tickgrid. Defaults to `False` + :param bool showtext: displays the tick text. Defaults to `False` + :param int decimal_points: number of decimal points to show. Defaults to :const:`0` + .. code-block:: python - plot.tick_params(tickx_height=12, tickcolor=0xFF0008) + plot.tick_params(tickx_height=6, ticky_height=6, tickcolor=0x000000) + +.. image:: ../docs/ticks_params.png + +Be aware that ticks are not shown by default. If you want to show them you need to add a graph to the plot. Gridlines are normally ``OFF``. If you want visible gridlines then use: @@ -133,6 +147,20 @@ Gridlines are normally ``OFF``. If you want visible gridlines then use: plot.tick_params(tickgrid=True) +If you want to show the axes text, you can use: + +.. code-block:: python + + plot.tick_params(showtext=True) + +If you want to show some decimal places in the text use: + +.. code-block:: python + + plot.tick_params(decimal_points=2) + +.. image:: ../docs/grid_text.png + Colors =============== You can choose some colors directly from the library. This can be done by importing the color class: @@ -152,33 +180,39 @@ This will allow you to use the colors in the list as color variable definitions * ORANGE * TEAL * GRAY + * PINK + * LIGHT_GRAY + * BROWN + * DARK_GREEN + * TURQUOISE + * DARK_BLUE + * DARK_RED + .. code-block:: python plot = Plot(0, 0, display.width, display.height, background_color=color.WHITE, box_color=color.BLACK) - +.. image:: ../docs/colors.png =========== Cartesian =========== -With the cartesian class it's possible to add (x,y) plots. You can add different (x,y) plots to the -same plot area. After you create your plot area you will need to define the xy plane -for the plot. Secondly, you will need to give some ``x`` and ``y`` data. -This data will be converted to a `ulab.numpy.ndarray`. For more information please refer -to the `ulab` library +With the cartesian class is possible to add (x,y) plots. You add it to the plot area created as explained +above. Then you will need to give some ``x`` and ``y`` data. The following code + .. code-block:: python from ulab import numpy as np from circuitpython_uplot.plot import Plot from circuitpython_uplot.cartesian import Cartesian + display = board.DISPLAY plot = Plot(0, 0, display.width, display.height) - x = np.linspace(-4, 4, num=25) - constant = 1.0 / np.sqrt(2 * np.pi) - y = constant * np.exp((-(x**2)) / 2.0) + x = [0, 1, 2, 3] + y = [0, 2, 4, 6] After the initial setup we add our xy plane and show our plot @@ -187,10 +221,13 @@ After the initial setup we add our xy plane and show our plot Cartesian(plot, x, y) display.show(plot) +You can add more than one graph to the same plot. Howver, you need to define the range of the graph as the two +graphs will share the same axes. There are some parameters that you can customize: - * rangex and rangey: you could specify the ranges of your graph. Allowing you to move your graph according to your needs. This parameters only accept lists - * line color: you could specify the color in HEX + * rangex and rangey: you could specify the ranges of your graph. Allowing you to move your graph according to your needs. This parameters only accept lists. This is needed for plotting more than one curve in the plot area. + * line color: you could specify the color in HEX. Or you could use the color class as explained above. + * line style: you could specify the line style. The default is a solid line. see below for more details * fill: if you selected this as `True` the area under your graph will be filled * nudge: this parameter allows yuo to move a little bit the graph. This is useful when the data start/end in the limits of your range @@ -214,10 +251,44 @@ if you want to add more than un line to your plot, you could do something like t x = np.linspace(-4, 4, num=25) y1 = x**2 / 2 y2 = 2 + x**2 + 3 * x - Cartesian(plot, x, y1) - Cartesian(plot, x, y1) + Cartesian(plot, x, y1, rangex=[-5, 5], rangey=[0, 1]) + Cartesian(plot, x, y2, rangex=[-5, 5], rangey=[0, 1]) display.show(plot) +if you need to override the ticks automatic rendering, you can use the following code: + +.. code-block:: python + + plot = Plot(0, 0, display.width, display.height) + x = np.linspace(-4, 4, num=25) + y1 = x**2 / 2 + Cartesian(plot, x, y1, ticksx=[-4, -2, 0, 2, 4], ticksy=[0, 5, 10, 15, 20]) + + display.show(plot) + +If you are adding more than one curve to the plot ticks will be defined for all curves. +And needs to be defined in the first cartesian graph added to the plot. + +Line styles +============ +You can select the line style of your Cartesian graph. The following line styles are available: + * SOLID + * DOTTED + * DASHED + * DASH_DOT + +This can be done by importing the color class, from the cartesian library: + +.. code-block:: python + + from circuitpython_uplot.cartesian import LineStyle + +You can select a dotted line by using the following code: ``line_style=LineStyle.DOTTED``. + +.. code-block:: python + + Cartesian(plot, x, y, line_style=LineStyle.DOTTED) + =============== Pie Chart @@ -264,8 +335,9 @@ Creates a scatter plot with x,y data. You can customize the circle diameter if y There are some parameters that you can customize: * rangex and rangey: you can specify the ranges of your graph. This allows you to move your graph according to your needs. This parameters only accept lists - * radius: circles radius/radii - * circle_color: you can specify the color in HEX + * radius: circles radius/radii. If a different value is given for each point, the radius should be a list of values. If selected pointer is not a circle, this parameter will be ignored + * pointer_color: you can specify the color in HEX. Or you could use the color class as explained above. + * pointer: you can select the pointer shape. The default is a circle. See below for more details * nudge: this parameter allows you to move the graph slighty. This is useful when the data start/end in the limits of your range @@ -275,14 +347,35 @@ There are some parameters that you can customize: z = [4, 5, 6, 7, 8] radi = [choice(z) for _ in a] b = [choice(a) for _ in a] - Scatter(plot, a, b, rangex=[0,210], rangey=[0, 210], radius=radi, circle_color=0xF456F3) + Scatter(plot, a, b, rangex=[0,210], rangey=[0, 210], radius=radi, pointer_color=0xF456F3) + + +Pointer styles +============== +You can select the pointer style of your Scatter graph. The following pointer styles are available: + * CIRCLE + * SQUARE + * TRIANGLE + * DIAMOND + +This can be done by importing the color class, from the cartesian library: + +.. code-block:: python + + from circuitpython_uplot.scatter import Pointer + +You can select a square pointer using the following code: ``pointer=Pointer.SQUARE``. + +.. code-block:: python + + Scatter(plot, a, b, pointer=Pointer.SQUARE) =============== Bar Plot =============== Allows you to graph bar plots. You just need to give the values of the bar in a python list. -You can choose to create shell or filled bars. +You can choose to create shell or filled bars or 3D projected bars. .. code-block:: python @@ -299,21 +392,21 @@ You can choose to create shell or filled bars. Bar(plot, a, b) -You can select the color or and if the bars are filled +You can select the color or/and if the bars are filled .. code-block:: python - Bar(plot, a, b, 0xFF1000, True) + Bar(plot, a, b, color=0xFF1000, fill=True) You can also select the bar spacing and the xstart position: .. code-block:: python - Bar(plot, a, b, 0xFF1000, fill=True, bar_space=30, xstart=70) + Bar(plot, a, b, color=0xFF1000, fill=True, bar_space=30, xstart=70) For bar filled graphs you can pass a color_palette list. This will allow you to select the color of each bar -This will not work for shell bars sadly. +This will not work for shell bars. .. code-block:: python @@ -326,7 +419,7 @@ This will not work for shell bars sadly. Bar(plot, a, b, fill=True, bar_space=30, xstart=70, color_palette=[0xFF1000, 0x00FF00, 0x0000FF, 0x00FFFF]) -with the projection argument you can show the bars with projection. This will give them a 3D +With the projection argument you can show the bars with projection. This will give them a 3D appearance .. code-block:: python @@ -344,7 +437,7 @@ appearance Bar(plot, a, b, color=0xFF1000, fill=True, bar_space=30, xstart=70, projection=True) -For filled unprojected bars you can update their values. This is useful for data logging. +For filled unprojected bars you can update their values in real time. This is useful for data logging. The max_value argument will allow you to set the maximum value of the graph. The plot will scale according to this max value, and bar plot will update their values accordingly @@ -362,7 +455,7 @@ according to this max value, and bar plot will update their values accordingly b = [3, 5, 1, 7] my_bar = Bar(plot, a, b, color=0xFF1000, fill=True, color_palette=[0xFF1000, 0x00FF00, 0xFFFF00, 0x123456], max_value=10) -Then you can update the values of the bar plot: +Then you can update the values of the bar plot in a loop: .. code-block:: python @@ -376,15 +469,12 @@ code will change all the bar's color to red my_bar.update_colors(0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000) -If you prefer, you can change the color of a single bar using the following code: +If you prefer, you can change the color of a single bar using the code below that will change the first bar to Blue.: .. code-block:: python my_bar.update_bar_color(0, 0x0000FF) -This will change the first bar to Blue. - - =============== Fillbetween @@ -504,3 +594,17 @@ For example, if you want to load the Temperature icon with a scale of 2 plot = Plot(0, 0, display.width, display.height) SVG(plot, Temperature, 250, 50, 2) display.show(plot) + +=============== +SHADE +=============== +Shade is a small module to add a shaded area to the plot. This is useful to highlight a specific area in the plot. +By itself will only fill rectangular areas in the plot area. However, it can be used in conjunction with other modules to create +more complex plots. Refer to the examples for more details. + +===================== +Polar Plot +===================== + +Allows to plot polar graphs. You just need to give the values of the graph in a python list. +See the examples folder for more information. diff --git a/docs/readme3.png b/docs/readme3.png new file mode 100644 index 0000000..2c469a3 Binary files /dev/null and b/docs/readme3.png differ diff --git a/docs/readme4.png b/docs/readme4.png new file mode 100644 index 0000000..52a764e Binary files /dev/null and b/docs/readme4.png differ diff --git a/docs/scatter_circle_radius.jpg b/docs/scatter_circle_radius.jpg new file mode 100644 index 0000000..feaf08b Binary files /dev/null and b/docs/scatter_circle_radius.jpg differ diff --git a/docs/scatter_pointers.jpg b/docs/scatter_pointers.jpg new file mode 100644 index 0000000..6851394 Binary files /dev/null and b/docs/scatter_pointers.jpg differ diff --git a/docs/scatter_using_different_datasets.jpg b/docs/scatter_using_different_datasets.jpg new file mode 100644 index 0000000..fef7a16 Binary files /dev/null and b/docs/scatter_using_different_datasets.jpg differ diff --git a/docs/uplot_shade.jpg b/docs/shade.jpg similarity index 100% rename from docs/uplot_shade.jpg rename to docs/shade.jpg diff --git a/docs/uplot_ex12.jpg b/docs/stackplot_example.jpg similarity index 100% rename from docs/uplot_ex12.jpg rename to docs/stackplot_example.jpg diff --git a/docs/uplot_svg.jpg b/docs/svg.jpg similarity index 100% rename from docs/uplot_svg.jpg rename to docs/svg.jpg diff --git a/docs/uplot_ex3.jpg b/docs/tickparameters.jpg similarity index 100% rename from docs/uplot_ex3.jpg rename to docs/tickparameters.jpg diff --git a/docs/ticks_params.png b/docs/ticks_params.png new file mode 100644 index 0000000..1d93a9e Binary files /dev/null and b/docs/ticks_params.png differ diff --git a/docs/uplot_ex16.jpg b/docs/uboxplot_example.jpg similarity index 100% rename from docs/uplot_ex16.jpg rename to docs/uboxplot_example.jpg diff --git a/docs/uplot_ex10.jpg b/docs/uplot_ex10.jpg deleted file mode 100644 index 732ac23..0000000 Binary files a/docs/uplot_ex10.jpg and /dev/null differ diff --git a/examples/uplot_bar_3Dbars.py b/examples/bar_3Dbars.py similarity index 72% rename from examples/uplot_bar_3Dbars.py rename to examples/bar_3Dbars.py index 907de9b..1f5834a 100644 --- a/examples/uplot_bar_3Dbars.py +++ b/examples/bar_3Dbars.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board from circuitpython_uplot.plot import Plot from circuitpython_uplot.bar import Bar @@ -19,11 +18,16 @@ b = [3, 5, 1, 9, 7] # Creating a 3D bar -Bar(plot, a, b, color=0xFF1000, fill=True, bar_space=30, xstart=70, projection=True) +Bar( + plot, + a, + b, + color=0xFF1000, + fill=True, + bar_space=30, + xstart=70, + projection=True, +) # Plotting and showing the plot -display.show(plot) - -# Adding some wait time -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/uplot_bar_color_changing.py b/examples/bar_color_changing.py similarity index 84% rename from examples/uplot_bar_color_changing.py rename to examples/bar_color_changing.py index 4563aae..69c5571 100644 --- a/examples/uplot_bar_color_changing.py +++ b/examples/bar_color_changing.py @@ -32,7 +32,7 @@ a = ["a", "b", "c", "d", "e", "f"] # Showing the plot -display.show(plot) +display.root_group = plot # Creating the bar my_bar = Bar( @@ -47,7 +47,14 @@ time.sleep(2) # Changing all the bars to Yellow my_bar.update_colors( - [color.YELLOW, color.YELLOW, color.YELLOW, color.YELLOW, color.YELLOW, color.YELLOW] + [ + color.YELLOW, + color.YELLOW, + color.YELLOW, + color.YELLOW, + color.YELLOW, + color.YELLOW, + ] ) time.sleep(2) diff --git a/examples/uplot_bar_colorpalette.py b/examples/bar_colorpalette.py similarity index 96% rename from examples/uplot_bar_colorpalette.py rename to examples/bar_colorpalette.py index 6fa245e..c10b948 100644 --- a/examples/uplot_bar_colorpalette.py +++ b/examples/bar_colorpalette.py @@ -39,4 +39,4 @@ ) # Showing the plot -display.show(plot) +display.root_group = plot diff --git a/examples/uplot_bar_example.py b/examples/bar_example.py similarity index 84% rename from examples/uplot_bar_example.py rename to examples/bar_example.py index 4345cfd..8ab8e1e 100644 --- a/examples/uplot_bar_example.py +++ b/examples/bar_example.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board from circuitpython_uplot.plot import Plot from circuitpython_uplot.bar import Bar @@ -20,8 +19,4 @@ Bar(plot, a, b, 0xFF1000, True) # Plotting and showing the plot -display.show(plot) - -# Adding some wait time -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/uplot_bar_scale_example.py b/examples/bar_scale_example.py similarity index 89% rename from examples/uplot_bar_scale_example.py rename to examples/bar_scale_example.py index fb7a90f..8cb0c99 100644 --- a/examples/uplot_bar_scale_example.py +++ b/examples/bar_scale_example.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board import displayio from circuitpython_uplot.plot import Plot @@ -30,8 +29,4 @@ group.append(plot_scale1) group.append(plot_scale2) -display.show(group) - -# Adding some wait time -while True: - time.sleep(1) +display.root_group = group diff --git a/examples/uplot_bar_updating_values.py b/examples/bar_updating_values.py similarity index 97% rename from examples/uplot_bar_updating_values.py rename to examples/bar_updating_values.py index 6f4bf27..1684eb9 100644 --- a/examples/uplot_bar_updating_values.py +++ b/examples/bar_updating_values.py @@ -31,7 +31,7 @@ add = 1 # Showing the plot -display.show(plot) +display.root_group = plot # Creating the bar my_bar = Bar( diff --git a/examples/cartersian_and_scatter_polyfit_example.py b/examples/cartersian_and_scatter_polyfit_example.py new file mode 100644 index 0000000..8da765a --- /dev/null +++ b/examples/cartersian_and_scatter_polyfit_example.py @@ -0,0 +1,122 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT + +import board +import displayio +from ulab import numpy as np +from table import Table +from circuitpython_uplot.plot import Plot +from circuitpython_uplot.scatter import Scatter +from circuitpython_uplot.cartesian import Cartesian + +# In order to run this example you need to install the following libraries: +# - adafruit_display_text +# - adafruit_bitmap_font +# - CircuitPython_TABLE (from https://github.com/jposada202020/CircuitPython_TABLE) + +g = displayio.Group() + +table_width = 125 + +# Setting up the display +display = board.DISPLAY + +# Adding the plot area +plot = Plot(0, 0, display.width - table_width, display.height, padding=1) +plot.tick_params(tickx_height=12, ticky_height=12, tickcolor=0x939597, tickgrid=True) +plot_table = Plot( + display.width - table_width - 1, + 0, + table_width - 1, + display.height, + padding=1, +) + +display.root_group = g +g.append(plot) +g.append(plot_table) + + +general_rangex = [0, 17] +general_rangey = [0, 70] + +# Creating the values +x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) +y = np.array([3, 14, 23, 25, 23, 15, 9, 5, 9, 13, 17, 24, 32, 36, 46]) + +# Creating the table +# To use the font, create a fonts directory in the root of the CIRCUITPY drive, +# and add the font file from the fonts folder +# fmt: off +my_table = Table( + 10, + 10, + 140, + 315, + [("-----------", "-----------",)], + [("Value X", "Value Y",), ("1", "3",), ("2", "14",),("3", "23",),("4", "25",), + ("5", "23",),("6", "15",),("7", "9",),("8", "5",),("9", "9",),("10", "13",), + ("11", "17",),("12", "24",),("13", "32",),("14", "36",), + ("15", "46",)], + "fonts/LibreBodoniv2002-Bold-10.bdf", + text_color = 0xFFFFFF, +) +# fmt: on +plot_table.append(my_table) + +# Polyfit Curve third degree +z = np.polyfit(x, y, 3) +new_x = np.linspace(0, 16, 50) +fit = z[0] * new_x**3 + z[1] * new_x**2 + z[2] * new_x + z[3] +Cartesian(plot, new_x, fit, rangex=general_rangex, rangey=general_rangey) + +# Polyfit Curve Second degree +z = np.polyfit(x, y, 2) +new_x = np.linspace(0, 16, 50) +fit = z[0] * new_x**2 + z[1] * new_x + z[2] +Cartesian(plot, new_x, fit, rangex=general_rangex, rangey=general_rangey) + +# Polyfit Curve First degree +z = np.polyfit(x, y, 1) +new_x = np.linspace(0, 16, 50) +fit = z[0] * new_x + z[1] +Cartesian(plot, new_x, fit, rangex=general_rangex, rangey=general_rangey) + +# Adding the Scatter Plot +Scatter( + plot, + x, + y, + rangex=general_rangex, + rangey=general_rangey, + pointer="triangle", + pointer_color=0x00FFFF, +) + +# Adding the labels for the Polylines +# change the x and y values to move the text according to your needs +plot.show_text( + "Polyfit 1", + x=300, + y=10, + anchorpoint=(0.5, 0.0), + text_color=0x149F14, + free_text=True, +) +plot.show_text( + "Polyfit 2", + x=72, + y=270, + anchorpoint=(0.0, 0.0), + text_color=0x647182, + free_text=True, +) +plot.show_text( + "Polyfit 3", + x=175, + y=200, + anchorpoint=(0.5, 0.0), + text_color=0x7428EF, + free_text=True, +) diff --git a/examples/uplot_cartesian_advanced.py b/examples/cartesian_advanced.py similarity index 90% rename from examples/uplot_cartesian_advanced.py rename to examples/cartesian_advanced.py index 4d2e51b..61d2948 100644 --- a/examples/uplot_cartesian_advanced.py +++ b/examples/cartesian_advanced.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board from ulab import numpy as np from circuitpython_uplot.plot import Plot @@ -27,8 +26,4 @@ Cartesian(plot, x, y, rangex=[-5, 5], rangey=[0, 1], line_color=0x00FF00) # Plotting and showing the plot -display.show(plot) - -# Adding some wait time -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/cartesian_fill.py b/examples/cartesian_fill.py new file mode 100644 index 0000000..65f5c4a --- /dev/null +++ b/examples/cartesian_fill.py @@ -0,0 +1,34 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT + +import board +from ulab import numpy as np +from circuitpython_uplot.plot import Plot +from circuitpython_uplot.cartesian import Cartesian + + +# Setting up the display +display = board.DISPLAY + +# Adding the plot area +plot = Plot(0, 0, display.width - 125, display.height, padding=25) + +display.root_group = plot + +# Creating the values +x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) +y = np.array([3, 14, 23, 25, 23, 15, 9, 5, 9, 13, 17, 24, 32, 36, 46]) + +# Polyfit Curve third degree +z = np.polyfit(x, y, 3) +new_x = np.linspace(0, 15, 50) +fit = z[0] * new_x**3 + z[1] * new_x**2 + z[2] * new_x + z[3] +Cartesian( + plot, + new_x, + fit, + rangex=[0, 15], + rangey=[0, 70], + fill=True, +) diff --git a/examples/cartesian_koch.py b/examples/cartesian_koch.py new file mode 100644 index 0000000..f690375 --- /dev/null +++ b/examples/cartesian_koch.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT + +# Example adapted to use in CircuitPython and Microplot from +# https://github.com/TheAlgorithms/Python/blob/master/fractals/koch_snowflake.py +# License MIT + +import board +from ulab import numpy +from circuitpython_uplot.plot import Plot +from circuitpython_uplot.cartesian import Cartesian + + +def iterate(initial_vectors: list[numpy.ndarray], steps: int) -> list[numpy.ndarray]: + vectors = initial_vectors + for _ in range(steps): + vectors = iteration_step(vectors) + return vectors + + +def iteration_step(vectors: list[numpy.ndarray]) -> list[numpy.ndarray]: + new_vectors = [] + for i, start_vector in enumerate(vectors[:-1]): + end_vector = vectors[i + 1] + new_vectors.append(start_vector) + difference_vector = end_vector - start_vector + new_vectors.append(start_vector + difference_vector / 3) + new_vectors.append( + start_vector + difference_vector / 3 + rotate(difference_vector / 3, 60) + ) + new_vectors.append(start_vector + difference_vector * 2 / 3) + new_vectors.append(vectors[-1]) + + return new_vectors + + +def rotate(vector: numpy.ndarray, angle_in_degrees: float) -> numpy.ndarray: + theta = numpy.radians(angle_in_degrees) + c, s = numpy.cos(theta), numpy.sin(theta) + rotation_matrix = numpy.array(((c, -s), (s, c))) + return numpy.dot(rotation_matrix, vector) + + +# Setting up the display +display = board.DISPLAY +plot = Plot(0, 0, 200, 200, padding=0) + +# initial triangle of Koch snowflake +VECTOR_1 = numpy.array([0, 0]) +VECTOR_2 = numpy.array([0.5, 0.8660254]) +VECTOR_3 = numpy.array([1, 0]) +INITIAL_VECTORS = [VECTOR_1, VECTOR_2, VECTOR_3, VECTOR_1] +# uncomment for simple Koch curve instead of Koch snowflake +# INITIAL_VECTORS = [VECTOR_1, VECTOR_3] + +# Due to memory restrictions the maximum number of iterations is 3. +processed_vectors = iterate(INITIAL_VECTORS, 3) +x_coordinates, y_coordinates = zip(*processed_vectors) + +# Adding the Cartesian plot +Cartesian(plot, x_coordinates, y_coordinates) +display.root_group = plot diff --git a/examples/cartesian_koch_2.py b/examples/cartesian_koch_2.py new file mode 100644 index 0000000..28cb4b2 --- /dev/null +++ b/examples/cartesian_koch_2.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT +# pylint: disable=unused-argument, use-dict-literal +# Example adapted to use in CircuitPython and Microplot from +# Heltonbiker +# https://stackoverflow.com/questions/7409938/fractal-koch-curve + +import math +import board +from circuitpython_uplot.plot import Plot +from circuitpython_uplot.cartesian import Cartesian + +angles = [math.radians(60 * x) for x in range(6)] +sines = [math.sin(x) for x in angles] +cosin = [math.cos(x) for x in angles] + + +def L(angle, coords, jump): + return (angle + 1) % 6 + + +def R(angle, coords, jump): + return (angle + 4) % 6 + + +def F(angle, coords, jump): + coords.append( + ( + coords[-1][0] + jump * cosin[angle], + coords[-1][1] + jump * sines[angle], + ) + ) + return angle + + +decode = dict(L=L, R=R, F=F) + + +def koch(steps, length=200, startPos=(0, 0)): + pathcodes = "F" + for _ in range(steps): + pathcodes = pathcodes.replace("F", "FLFRFLF") + + jump = float(length) / (3**steps) + coords = [startPos] + angle = 0 + + for move in pathcodes: + angle = decode[move](angle, coords, jump) + + return coords + + +TOTALWIDTH = 300 +display = board.DISPLAY +plot = Plot(0, 0, display.width, display.height, padding=0) +points = koch(5, TOTALWIDTH, (-TOTALWIDTH / 2, 0)) +x_coordinates, y_coordinates = zip(*points) + +# Adding the Cartesian plot +Cartesian(plot, x_coordinates, y_coordinates) +display.root_group = plot diff --git a/examples/uplot_cartesian_loggin_data.py b/examples/cartesian_logging_data.py similarity index 99% rename from examples/uplot_cartesian_loggin_data.py rename to examples/cartesian_logging_data.py index 1937820..72f1b28 100644 --- a/examples/uplot_cartesian_loggin_data.py +++ b/examples/cartesian_logging_data.py @@ -79,7 +79,7 @@ g.append(plot_1) g.append(plot_2) -display.show(g) +display.root_group = g display.refresh() for i, element in enumerate(x): diff --git a/examples/uplot_cartesian_table.py b/examples/cartesian_table.py similarity index 99% rename from examples/uplot_cartesian_table.py rename to examples/cartesian_table.py index 142837d..359621d 100644 --- a/examples/uplot_cartesian_table.py +++ b/examples/cartesian_table.py @@ -119,4 +119,4 @@ def heat_index(temp, humidity): color.BLUE, ) g.append(my_table) -display.show(g) +display.root_group = g diff --git a/examples/cartesian_trig_functions.py b/examples/cartesian_trig_functions.py index 67c85b3..02e0206 100644 --- a/examples/cartesian_trig_functions.py +++ b/examples/cartesian_trig_functions.py @@ -39,4 +39,4 @@ g.append(text_area) g.append(text2_area) -display.show(g) +display.root_group = g diff --git a/examples/uplot_display_shapes.py b/examples/display_shapes.py similarity index 92% rename from examples/uplot_display_shapes.py rename to examples/display_shapes.py index 0d2686f..c49d65c 100644 --- a/examples/uplot_display_shapes.py +++ b/examples/display_shapes.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board from adafruit_display_shapes.polygon import Polygon from adafruit_display_shapes.roundrect import RoundRect @@ -42,8 +41,4 @@ plot.append(roundrect) # Plotting and showing the plot -display.show(plot) - -# Adding some wait time -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/uplot_fillbetween.py b/examples/fillbetween.py similarity index 83% rename from examples/uplot_fillbetween.py rename to examples/fillbetween.py index 696b7bb..a6a5ccc 100644 --- a/examples/uplot_fillbetween.py +++ b/examples/fillbetween.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board from ulab import numpy as np from circuitpython_uplot.plot import Plot @@ -21,8 +20,4 @@ Fillbetween(plot, x, y1, y2) -display.show(plot) - -# Adding some wait time -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/uplot_integration_example.py b/examples/integration_example.py similarity index 95% rename from examples/uplot_integration_example.py rename to examples/integration_example.py index 0982a09..b26b25c 100644 --- a/examples/uplot_integration_example.py +++ b/examples/integration_example.py @@ -31,7 +31,4 @@ plot.draw_circle(radius=8, x=120, y=120) # Showing in the screen -display.show(plot) - -while True: - pass +display.root_group = plot diff --git a/examples/lissajous_curves.py b/examples/lissajous_curves.py index cc9272f..945f120 100644 --- a/examples/lissajous_curves.py +++ b/examples/lissajous_curves.py @@ -48,7 +48,7 @@ def create_curve(a=1, b=2, mul_factor=10, delta=3.14 / 2): g.append(plot4) # Plotting and showing the plot -display.show(g) +display.root_group = g # Some Variables diff --git a/examples/uplot_logging_animation.py b/examples/logging_animation.py similarity index 91% rename from examples/uplot_logging_animation.py rename to examples/logging_animation.py index 225d43a..ad79397 100644 --- a/examples/uplot_logging_animation.py +++ b/examples/logging_animation.py @@ -14,11 +14,11 @@ # Drawing the graph my_plot = Plot( - 140, - 60, - 200, - 200, - padding=1, + 5, + 5, + 480, + 300, + padding=20, show_box=True, box_color=color.WHITE, ) @@ -29,6 +29,7 @@ ticky_height=4, show_ticks=True, tickcolor=color.TEAL, + tickgrid=True, showtext=True, ) @@ -60,7 +61,7 @@ random_numbers = [19, 22, 35, 33, 24, 26, 28, 37] -display.show(my_plot) +display.root_group = my_plot display.refresh() dist = 1 @@ -75,10 +76,11 @@ line_color=color.BLUE, ticksx=[25, 50, 75, 100, 125, 150, 175, 200], ticksy=[25, 50, 75, 100], + fill=False, ) # Showing the loggraph -while True: +for _ in range(20): if dist > len(x): y.pop(0) y.append(random.choice(random_numbers)) diff --git a/examples/uplot_logging_changing_values.py b/examples/logging_changing_values.py similarity index 97% rename from examples/uplot_logging_changing_values.py rename to examples/logging_changing_values.py index 945e4b9..7d1858e 100644 --- a/examples/uplot_logging_changing_values.py +++ b/examples/logging_changing_values.py @@ -48,7 +48,7 @@ g.append(plot_1) -display.show(g) +display.root_group = g display.refresh() my_log = Logging( @@ -63,7 +63,7 @@ ) -while True: +for i in range(2): for i in range(len(x)): my_log.draw_points(plot_1, x[0:i], temp_y[0:i]) time.sleep(1) diff --git a/examples/uplot_logging_fill.py b/examples/logging_fill.py similarity index 96% rename from examples/uplot_logging_fill.py rename to examples/logging_fill.py index 24a2d5e..10885fe 100644 --- a/examples/uplot_logging_fill.py +++ b/examples/logging_fill.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +import time import displayio import board from circuitpython_uplot.plot import Plot, color @@ -12,7 +13,6 @@ group = displayio.Group() - palette = displayio.Palette(1) palette[0] = 0x000000 @@ -77,4 +77,6 @@ group.append(plot_1) group.append(plot_2) -display.show(group) +display.root_group = group + +time.sleep(10) diff --git a/examples/logging_limits.py b/examples/logging_limits.py new file mode 100644 index 0000000..0ccf9de --- /dev/null +++ b/examples/logging_limits.py @@ -0,0 +1,90 @@ +# SPDX-FileCopyrightText: Copyright (c) Jose D. Montoya +# +# SPDX-License-Identifier: MIT + + +import time +import random +import board +from circuitpython_uplot.plot import Plot, color +from circuitpython_uplot.logging import Logging + +# Setting up the display +display = board.DISPLAY +display.auto_refresh = False + +# Drawing the graph +my_plot = Plot( + 140, + 60, + 200, + 200, + show_box=True, + box_color=color.WHITE, +) + +# Setting the tick parameters +my_plot.tick_params( + tickx_height=4, + ticky_height=4, + show_ticks=True, + tickcolor=color.TEAL, + showtext=True, +) + +# Creating the x and y data +x = [ + 10, + 20, + 30, + 40, + 50, + 60, + 70, + 80, + 90, + 100, + 110, + 120, + 130, + 140, + 150, + 160, + 170, + 180, + 190, +] +y = [26, 32, 34, 30, 28, 35, 46, 65, 37, 23, 40, 27, 26, 36, 44, 53, 69, 27, 26] + +# Creating the random numbers +random_numbers = [32, 34, 45, 65, 24, 40, 18, 27] + + +display.root_group = my_plot +display.refresh() + +dist = 1 + +# Creating the loggraph +my_loggraph = Logging( + my_plot, + x[0:dist], + y[0:dist], + rangex=[0, 210], + rangey=[0, 110], + line_color=color.BLUE, + ticksx=[25, 50, 75, 100, 125, 150, 175, 200], + ticksy=[25, 50, 75, 100], + limits=[30, 60], +) + +# Showing the loggraph +for i in range(45): + if dist > len(x): + y.pop(0) + y.append(random.choice(random_numbers)) + + my_loggraph.draw_points(my_plot, x[0:dist], y[0:dist]) + display.refresh() + dist += 1 + time.sleep(0.5) diff --git a/examples/uplot_logging.py b/examples/logging_simple_test.py similarity index 97% rename from examples/uplot_logging.py rename to examples/logging_simple_test.py index 69655a6..cbd6a63 100644 --- a/examples/uplot_logging.py +++ b/examples/logging_simple_test.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +import time import displayio import terminalio import board @@ -9,6 +10,7 @@ from circuitpython_uplot.plot import Plot, color from circuitpython_uplot.logging import Logging + # Setting up the display display = board.DISPLAY @@ -58,8 +60,8 @@ g.append(plot_1) -display.show(g) -display.refresh() +display.root_group = g + dist = 3 @@ -75,3 +77,5 @@ ) text_temperature.text = "{}C".format(temp_y[dist]) + +time.sleep(5) diff --git a/examples/uplot_logging_table.py b/examples/logging_table.py similarity index 97% rename from examples/uplot_logging_table.py rename to examples/logging_table.py index 962fee3..5c997b8 100644 --- a/examples/uplot_logging_table.py +++ b/examples/logging_table.py @@ -74,9 +74,9 @@ g.append(plot_1) g.append(my_table) # Show the group -display.show(g) +display.root_group = g -while True: +for _ in range(2): for i in range(len(x)): my_log.draw_points(plot_1, x[0:i], temp_y[0:i]) time.sleep(1) diff --git a/examples/logging_with_dial_gauge.py b/examples/logging_with_dial_gauge.py new file mode 100644 index 0000000..89389f6 --- /dev/null +++ b/examples/logging_with_dial_gauge.py @@ -0,0 +1,104 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT + +import time +import random +import board +import displayio +from dial_gauge import DIAL_GAUGE +from circuitpython_uplot.plot import Plot, color +from circuitpython_uplot.logging import Logging + + +# In order to run this example you need to install the following library: +# - CircuitPython_DIAL_GAUGE (from https://github.com/jposada202020/CircuitPython_DIAL_GAUGE) + +rangey_values = [0, 110] + +display = board.DISPLAY +display.auto_refresh = False +my_plot = Plot(0, 0, display.width // 2, display.height // 2) +plot2 = Plot(display.width // 2, 0, display.width // 2, display.height // 2) + +my_dial = DIAL_GAUGE(60, 50, 60, 40, range_values=rangey_values, color=color.BLUE) + +plot2.append(my_dial) + +g = displayio.Group() +g.append(my_plot) +g.append(plot2) +display.root_group = g + + +my_plot.tick_params( + tickx_height=4, + ticky_height=4, + show_ticks=True, + tickcolor=color.TEAL, + showtext=True, +) + +# Creating the x and y data +x = [ + 10, + 20, + 30, + 40, + 50, + 60, + 70, + 80, + 90, + 100, + 110, + 120, + 130, + 140, + 150, + 160, + 170, + 180, + 190, +] +y = [] + +# Creating the random numbers +random_numbers = [32, 34, 45, 65, 24, 40, 18, 27] + + +# display.show(my_plot) +display.refresh() + +dist = 0 + +# Creating the loggraph +my_loggraph = Logging( + my_plot, + x[0:dist], + y[0:dist], + rangex=[0, 210], + rangey=rangey_values, + line_color=color.BLUE, + ticksx=[25, 50, 75, 100, 125, 150, 175, 200], + ticksy=[25, 50, 75, 100], + limits=[30, 60], +) + +# Showing the loggraph +for i in range(150): + if dist > len(x): + y.pop(0) + + update_value = random.choice(random_numbers) + y.append(update_value) + + my_loggraph.draw_points(my_plot, x[0:dist], y[0:dist]) + + if dist > len(x): + my_dial.update(update_value) + else: + my_dial.update(y[i]) + display.refresh() + dist += 1 + time.sleep(0.5) diff --git a/examples/uplot_map.py b/examples/map.py similarity index 88% rename from examples/uplot_map.py rename to examples/map.py index 4eaacc1..03c0d8f 100644 --- a/examples/uplot_map.py +++ b/examples/map.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time from random import choice import board from ulab import numpy as np @@ -25,8 +24,4 @@ # Plotting and showing the plot Map(plot, y1, 0xFF0044, 0x4400FF) # Plotting and showing the plot -display.show(plot) - -# Adding some wait time -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/uplot_pie_example.py b/examples/pie_example.py similarity index 82% rename from examples/uplot_pie_example.py rename to examples/pie_example.py index ea177c8..b297610 100644 --- a/examples/uplot_pie_example.py +++ b/examples/pie_example.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board from circuitpython_uplot.plot import Plot from circuitpython_uplot.pie import Pie @@ -20,8 +19,4 @@ Pie(plot, a) # Plotting and showing the plot -display.show(plot) - -# Adding some wait time -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/uplot_plot_example.py b/examples/plot_example.py similarity index 89% rename from examples/uplot_plot_example.py rename to examples/plot_example.py index effe84e..b819e94 100644 --- a/examples/uplot_plot_example.py +++ b/examples/plot_example.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board from ulab import numpy as np from circuitpython_uplot.plot import Plot @@ -22,6 +21,4 @@ # Drawing the graph Cartesian(plot, x, y) -display.show(plot) -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/plot_line_styles.py b/examples/plot_line_styles.py new file mode 100644 index 0000000..d0532ac --- /dev/null +++ b/examples/plot_line_styles.py @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT + +import board +from ulab import numpy as np +from circuitpython_uplot.plot import Plot +from circuitpython_uplot.cartesian import Cartesian + +# Setting up the display +display = board.DISPLAY +plot = Plot(0, 0, display.width, display.height) + +# Creating some points to graph +x = np.linspace(-4, 4, num=25) +constant = 1.0 / np.sqrt(2 * np.pi) +y = constant * np.exp((-(x**2)) / 2.0) + +# Drawing the graph +Cartesian( + plot, + x, + y, + rangex=[-5, 5], + rangey=[0, 1], + line_color=0xFF0000, + line_style="- -", +) + +# Creating some points to graph +x = np.linspace(-3, 3, num=50) +constant = 2.0 / np.sqrt(2 * np.pi) +y = constant * np.exp((-(x**2)) / 2.0) +Cartesian( + plot, + x, + y, + rangex=[-5, 5], + rangey=[0, 1], + line_color=0x00FF00, + line_style=".", +) + + +x = np.linspace(-4, 4, num=50) +constant = 2.5 / np.sqrt(2 * np.pi) +y = constant * np.exp((-(x**2)) / 6.5) +Cartesian( + plot, + x, + y, + rangex=[-5, 5], + rangey=[0, 1], + line_color=0x123456, + line_style="-.-", +) + +# Plotting and showing the plot +display.root_group = plot diff --git a/examples/plot_simpletest.py b/examples/plot_simpletest.py index 80f91b8..6f06270 100644 --- a/examples/plot_simpletest.py +++ b/examples/plot_simpletest.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board from circuitpython_uplot.plot import Plot @@ -14,7 +13,4 @@ plot.draw_circle(radius=8, x=120, y=120) -display.show(plot) - -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/polar_advanced.py b/examples/polar_advanced.py index 107b003..4e88491 100644 --- a/examples/polar_advanced.py +++ b/examples/polar_advanced.py @@ -72,4 +72,4 @@ g.append(plot4) # Show the Display -display.show(g) +display.root_group = g diff --git a/examples/uplot_polar_example.py b/examples/polar_example.py similarity index 95% rename from examples/uplot_polar_example.py rename to examples/polar_example.py index 9117de1..0e761a2 100644 --- a/examples/uplot_polar_example.py +++ b/examples/polar_example.py @@ -17,4 +17,4 @@ # Plotting and showing the plot Polar(plot, theta, r, rangex=[-2, 2], rangey=[-2, 2], line_color=color.ORANGE) -display.show(plot) +display.root_group = plot diff --git a/examples/uplot_polar_plots.py b/examples/polar_plots.py similarity index 99% rename from examples/uplot_polar_plots.py rename to examples/polar_plots.py index 91d039e..3a8f4b2 100644 --- a/examples/uplot_polar_plots.py +++ b/examples/polar_plots.py @@ -25,7 +25,7 @@ g.append(plot4) # Plotting and showing the plot -display.show(g) +display.root_group = g def rose_function(n=3, angle_range=[0, 360], radius=30): diff --git a/examples/uplot_readme_example.py b/examples/readme_example.py similarity index 98% rename from examples/uplot_readme_example.py rename to examples/readme_example.py index 19771de..525b798 100644 --- a/examples/uplot_readme_example.py +++ b/examples/readme_example.py @@ -91,4 +91,4 @@ plot.append(plot7) # Plotting and showing the plot -display.show(plot) +display.root_group = plot diff --git a/examples/uplot_scatter.py b/examples/scatter.py similarity index 88% rename from examples/uplot_scatter.py rename to examples/scatter.py index 7bf7828..fb64566 100644 --- a/examples/uplot_scatter.py +++ b/examples/scatter.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time from random import choice import board from ulab import numpy as np @@ -24,8 +23,4 @@ Scatter(plot, a, b) # Plotting and showing the plot -display.show(plot) - -# Adding some wait time -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/scatter_circle_radius.py b/examples/scatter_circle_radius.py new file mode 100644 index 0000000..fb043b9 --- /dev/null +++ b/examples/scatter_circle_radius.py @@ -0,0 +1,33 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT + +from random import choice +import board +from ulab import numpy as np +from circuitpython_uplot.plot import Plot +from circuitpython_uplot.scatter import Scatter + + +# Setting up the display +display = board.DISPLAY + +# Adding the plot area +plot = Plot(0, 0, display.width, display.height, padding=1) +plot.tick_params(tickx_height=12, ticky_height=12, tickcolor=0x939597, tickgrid=True) + +display.root_group = plot + +a = np.linspace(1, 200, 150) +z = [4, 5, 6, 7, 8] +radi = [choice(z) for _ in a] +b = [choice(a) for _ in a] +Scatter( + plot, + a, + b, + rangex=[0, 210], + rangey=[0, 210], + radius=radi, + pointer_color=0xF456F3, +) diff --git a/examples/scatter_pointers.py b/examples/scatter_pointers.py new file mode 100644 index 0000000..1c429aa --- /dev/null +++ b/examples/scatter_pointers.py @@ -0,0 +1,39 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT + + +from random import choice +import displayio +import board +from ulab import numpy as np +from circuitpython_uplot.plot import Plot +from circuitpython_uplot.scatter import Scatter, Pointer + + +# Setting up the display +display = board.DISPLAY + +# Adding the plot area +plot = Plot(0, 0, display.width // 2, display.height // 2, padding=1) +plot.tick_params(tickx_height=12, ticky_height=12, tickcolor=0xFF0008, tickgrid=True) +plot2 = Plot(240, 0, display.width // 2, display.height // 2, padding=1) +plot2.tick_params(tickx_height=6, ticky_height=6, tickcolor=0x939597, tickgrid=True) +plot3 = Plot(0, 160, display.width // 2, display.height // 2, padding=1) +plot3.tick_params(tickx_height=6, ticky_height=6, tickcolor=0x939597, tickgrid=False) +plot4 = Plot(240, 160, display.width // 2, display.height // 2, padding=1) +g = displayio.Group() +g.append(plot) +g.append(plot2) +g.append(plot3) +g.append(plot4) +display.root_group = plot +# Setting up tick parameters + + +a = np.linspace(1, 100) +b = [choice(a) for _ in a] +Scatter(plot, a, b) +Scatter(plot2, a, b, pointer=Pointer.TRIANGLE, pointer_color=0x00FF00) +Scatter(plot3, a, b, pointer=Pointer.SQUARE, pointer_color=0xFFFFFF) +Scatter(plot4, a, b, pointer=Pointer.DIAMOND, pointer_color=0xFF32FF) diff --git a/examples/scatter_using_different_datasets.py b/examples/scatter_using_different_datasets.py new file mode 100644 index 0000000..4e88887 --- /dev/null +++ b/examples/scatter_using_different_datasets.py @@ -0,0 +1,69 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT + +from random import choice +import board +from ulab import numpy as np +from circuitpython_uplot.plot import Plot +from circuitpython_uplot.scatter import Scatter, Pointer + + +# Setting up the display +display = board.DISPLAY + +# Adding the plot area +plot = Plot(0, 0, display.width, display.height, padding=25) +plot.tick_params( + tickx_height=12, + ticky_height=12, + tickcolor=0x939597, + tickgrid=True, + showtext=True, + decimal_points=0, +) + +display.root_group = plot + +a = np.linspace(4, 200, 50) +z = [4, 5, 6, 7, 8] +radi = [choice(z) for _ in a] +b = [choice(a) for _ in a] +Scatter( + plot, + a, + b, + rangex=[0, 210], + rangey=[0, 210], + radius=radi, + pointer_color=0xF456F3, +) +a = np.linspace(50, 170, 50) +radi = [choice(z) for _ in a] +b = [choice(a) for _ in a] +Scatter( + plot, + a, + b, + rangex=[0, 210], + rangey=[0, 210], + radius=radi, + pointer_color=0x00FF00, +) +a = np.linspace(50, 100, 25) +z = [ + 4, + 5, + 6, +] +radi = [choice(z) for _ in a] +b = [int(choice(a) / 1.2) for _ in a] +Scatter( + plot, + a, + b, + rangex=[0, 210], + rangey=[0, 210], + pointer=Pointer.TRIANGLE, + pointer_color=0x00FFFF, +) diff --git a/examples/uplot_shade_example.py b/examples/shade_example.py similarity index 97% rename from examples/uplot_shade_example.py rename to examples/shade_example.py index b28722e..0ee113b 100644 --- a/examples/uplot_shade_example.py +++ b/examples/shade_example.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board from ulab import numpy as np from circuitpython_uplot.plot import Plot @@ -99,6 +98,4 @@ def heat_index(temp, humidity): for i in range(40, 110, 10): Cartesian(plot, x, heat_index(x, i), rangex=[25, 50], rangey=[25, 60]) -display.show(plot) -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/uplot_sparkline.py b/examples/sparkline.py similarity index 97% rename from examples/uplot_sparkline.py rename to examples/sparkline.py index 740b2cb..caa86c7 100644 --- a/examples/uplot_sparkline.py +++ b/examples/sparkline.py @@ -37,7 +37,7 @@ plot.append(sparkline) # Plotting and showing the plot -display.show(plot) +display.root_group = plot for element in y: display.auto_refresh = False diff --git a/examples/uplot_stackplot.py b/examples/stackplot.py similarity index 92% rename from examples/uplot_stackplot.py rename to examples/stackplot.py index b6bc0d8..34d5b00 100644 --- a/examples/uplot_stackplot.py +++ b/examples/stackplot.py @@ -5,7 +5,6 @@ Example to show how to draw stackplots """ -import time import board from ulab import numpy as np from circuitpython_uplot.plot import Plot @@ -28,7 +27,4 @@ Cartesian(plot, x, y, rangex=[0, 11], rangey=[0, 12], line_color=0x4444FF, fill=True) -display.show(plot) - -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/uplot_svg_example.py b/examples/svg_example.py similarity index 95% rename from examples/uplot_svg_example.py rename to examples/svg_example.py index a20fb75..098dda0 100644 --- a/examples/uplot_svg_example.py +++ b/examples/svg_example.py @@ -17,4 +17,4 @@ SVG(plot, Temperature, 250, 50, 2, color.GREEN) SVG(plot, Temperature2, 300, 50, 0.25, color.BLUE) -display.show(plot) +display.root_group = plot diff --git a/examples/uplot_tickparameters.py b/examples/tickparameters.py similarity index 90% rename from examples/uplot_tickparameters.py rename to examples/tickparameters.py index 2f51130..f7c40ed 100644 --- a/examples/uplot_tickparameters.py +++ b/examples/tickparameters.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -import time import board from ulab import numpy as np from circuitpython_uplot.plot import Plot, color @@ -33,8 +32,4 @@ Cartesian(plot, x, y, line_color=color.BLACK) # Plotting and showing the plot -display.show(plot) - -# Adding some wait time -while True: - time.sleep(1) +display.root_group = plot diff --git a/examples/uplot_uboxplot.py b/examples/uboxplot_example.py similarity index 93% rename from examples/uplot_uboxplot.py rename to examples/uboxplot_example.py index 20fb2c5..246c744 100644 --- a/examples/uplot_uboxplot.py +++ b/examples/uboxplot_example.py @@ -6,7 +6,7 @@ """ import board -from uboxplot import Boxplot +from boxplot import Boxplot from circuitpython_uplot.plot import Plot @@ -66,7 +66,4 @@ plot.append(my_box) plot.append(my_box2) plot.append(my_box3) -display.show(plot) - -while True: - pass +display.root_group = plot diff --git a/pyproject.toml b/pyproject.toml index cbabdd6..3478d03 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,24 +3,19 @@ # SPDX-License-Identifier: MIT [build-system] -requires = [ - "setuptools", - "wheel", - "setuptools-scm", -] +requires = ["setuptools", "wheel", "setuptools-scm"] [project] name = "circuitpython-uplot" description = "framework to display different plots in displayio. similar to widget" version = "0.0.0+auto.0" readme = "README.rst" -authors = [ - {name = "JDM", email = "uplot@mailmeto.mozmail.com"} -] -urls = {Homepage = "https://github.com/jposada202020/CircuitPython_uplot"} +authors = [{ name = "JDM", email = "uplot@mailmeto.mozmail.com" }] +urls = { Homepage = "https://github.com/jposada202020/CircuitPython_uplot" } keywords = [ "circuitpython", "uplot", + "microplot", "bar", "stackplot", "fillbetween", @@ -41,7 +36,7 @@ keywords = [ "plot", "plotter", ] -license = {text = "MIT"} +license = { text = "MIT" } classifiers = [ "Intended Audience :: Developers", "Topic :: Software Development :: Libraries", @@ -56,5 +51,5 @@ dynamic = ["dependencies", "optional-dependencies"] packages = ["circuitpython_uplot"] [tool.setuptools.dynamic] -dependencies = {file = ["requirements.txt"]} -optional-dependencies = {optional = {file = ["optional_requirements.txt"]}} +dependencies = { file = ["requirements.txt"] } +optional-dependencies = { optional = { file = ["optional_requirements.txt"] } }