diff --git a/.flake8 b/.flake8
index 14e338a..02e32eb 100644
--- a/.flake8
+++ b/.flake8
@@ -1,6 +1,6 @@
[flake8]
max-line-length = 120
-exclude = scratch.*, docs/
+exclude = scratch.py, docs/
ignore =
W503, # line break before binary operator
E203, # whitespace before ':'
diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml
index 99f0266..9125403 100644
--- a/.github/workflows/lint-and-test.yml
+++ b/.github/workflows/lint-and-test.yml
@@ -1,7 +1,7 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
-name: Lint and Test Python Library
+name: tests
on:
push:
@@ -33,7 +33,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- python -m pip install flake8 pytest coverage
+ python -m pip install flake8 pytest coverage html5lib
python -m pip install .
- name: Lint with flake8
run: |
@@ -46,11 +46,10 @@ jobs:
coverage run --append --source esparto -m pytest
- name: Install optional dependencies
run: |
- python -m pip install ipython pandas matplotlib bokeh plotly kaleido "weasyprint<53" beautifulsoup4 html5lib
- - name: Test full install with pytest
+ python -m pip install ipython pandas matplotlib bokeh plotly kaleido "weasyprint<53" html5lib
+ - name: Test full install with pytest
run: |
coverage run --append --source esparto -m pytest
- name: Upload coverage to codecov.io
run: |
bash <(curl -s https://codecov.io/bash)
-
diff --git a/.gitignore b/.gitignore
index 9fd168a..d226d6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,8 @@ esparto-doc.html
esparto-quick.html
esparto-doc.pdf
docs/examples/*.html
+/*.html
+/*.pdf
# IDE files
.vscode
@@ -113,3 +115,5 @@ ENV/
# mypy
.mypy_cache/
+.markdownlint.json
+my-report.html
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7f13e2c..5fdc290 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -31,6 +31,7 @@ repos:
language: system
entry: poetry run mypy
types: [python]
+ exclude: tests/
- id: version
name: Version
language: system
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 808810a..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-sudo: false
-language: python
-os: linux
-dist: xenial
-python:
- - 3.6
- - 3.7
- - 3.8
- - 3.9
-
-env:
- - EXTRA_INSTALLS=""
- - EXTRA_INSTALLS="ipython pandas matplotlib bokeh plotly kaleido weasyprint<53 beautifulsoup4 html5lib"
-
-install:
- - pip install . pytest coverage $EXTRA_INSTALLS
-
-script:
- - coverage run --append --source esparto -m pytest
-
-after_success:
- - bash <(curl -s https://codecov.io/bash)
diff --git a/Makefile b/Makefile
index 59cb7e6..4ac2e70 100644
--- a/Makefile
+++ b/Makefile
@@ -57,10 +57,10 @@ lint: ## check style with flake8
flake8 esparto tests
mypy: ## check type hints
- mypy esparto tests
+ mypy esparto --strict
isort: ## sort imports
- isort esparto tests
+ isort esparto tests --profile black
cqa: format isort lint mypy ## run all cqa tools
diff --git a/README.md b/README.md
index 2c0f35f..7198103 100644
--- a/README.md
+++ b/README.md
@@ -3,98 +3,131 @@ esparto
[![image](https://img.shields.io/pypi/v/esparto.svg)](https://pypi.python.org/pypi/esparto)
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/esparto.svg)](https://pypi.python.org/pypi/esparto/)
-[![Build Status](https://travis-ci.com/domvwt/esparto.svg?branch=main)](https://travis-ci.com/domvwt/esparto)
+![Build Status](https://github.com/domvwt/esparto/actions/workflows/lint-and-test.yml/badge.svg)
[![codecov](https://codecov.io/gh/domvwt/esparto/branch/main/graph/badge.svg?token=35J8NZCUYC)](https://codecov.io/gh/domvwt/esparto)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=domvwt_esparto&metric=alert_status)](https://sonarcloud.io/dashboard?id=domvwt_esparto)
![PyPI - Downloads](https://img.shields.io/pypi/dm/esparto)
+Introduction
+------------
-## Introduction
-**esparto** is a Python package for building shareable reports with content
-from popular data analysis libraries.
-With just a few lines of code, **esparto** turns DataFrames, plots, and
-Markdown into an interactive webpage or PDF document.
+**esparto** is a Python library for building data driven reports with content
+from popular analytics packages. The project takes a straightforward approach
+to document design; with a focus on usability, portability, and extensiblity.
-Documents produced by **esparto** are completely portable - no backend server
-is required - and entirely customisable using CSS and Jinja templating.
-All content dependencies are declared inline or loaded via a CDN, meaning your
-reports can be shared by email, hosted on a standard http server, or made
-available as static pages as-is.
+Creating a report is as simple as instantiating a Page object and 'adding' content
+in the form of DataFrames, plots, and markdown text. Documents can be built interactively
+in a notebook environment, and the results shared as a self-contained HTML
+page or PDF file.
+Further customisation of the output is possible by passing a CSS stylesheet,
+changing the [Jinja](Jinja) template, or declaring additional element styles within
+the code. The responsive [Bootstrap](Bootstrap) grid ensures documents adapt to
+any viewing device.
+
+Basic Usage
+-----------
-## Basic Usage
```python
import esparto as es
+
+# Do some analysis
+pandas_dataframe = ...
+plotly_figure = ...
+
+# Create a Page object
page = es.Page(title="My Report")
-page["Data Analysis"] = (pandas_dataframe, plotly_figure)
+
+# Add content
+page["Data Analysis"]["Plot"] = plotly_figure
+page["Data Analysis"]["Data"] = pandas_dataframe
+
+# Save to HTML or PDF
page.save_html("my-report.html")
+page.save_pdf("my-report.pdf")
+
```
+Main Features
+-------------
-## Main Features
-* Automatic and adaptive layout
-* Customisable with CSS or Jinja
-* Jupyter Notebook friendly
-* Output as HTML or PDF
-* Built-in adaptors for:
- * Markdown
- * Images
- * [Pandas DataFrames][Pandas]
- * [Matplotlib][Matplotlib]
- * [Bokeh][Bokeh]
- * [Plotly][Plotly]
+- Interactive document design with Jupyter Notebooks
+- Share as self-contained HTML or PDF
+- Customise with CSS and Jinja
+- Responsive Bootstrap grid layout
+- Content adaptors for:
+ - [Markdown][Markdown]
+ - [Images][Pillow]
+ - [Pandas DataFrames][Pandas]
+ - [Matplotlib][Matplotlib]
+ - [Bokeh][Bokeh]
+ - [Plotly][Plotly]
+Installation
+------------
-## Installation
**esparto** is available from [PyPI][PyPI] and [Conda][Conda]:
+
```bash
pip install esparto
```
+
```bash
conda install esparto -c conda-forge
```
-If PDF output is required, [Weasyprint](https://weasyprint.org/) must also be installed.
+Dependencies
+------------
+
+- [python](https://python.org/) >= 3.6
+- [jinja2](https://palletsprojects.com/p/jinja/)
+- [markdown](https://python-markdown.github.io/)
+- [BeautifulSoup](https://www.crummy.com/software/BeautifulSoup/)
+- [PyYAML](https://pyyaml.org/)
-## Dependencies
-* [python](https://python.org/) >= 3.6
-* [jinja2](https://palletsprojects.com/p/jinja/)
-* [markdown](https://python-markdown.github.io/)
-* [Pillow](https://python-pillow.org/)
-* [PyYAML](https://pyyaml.org/)
-* [weasyprint](https://weasyprint.org/) _(optional - required for PDF output)_
+#### Optional
+- [Pillow](https://python-pillow.org/) *(for image content)*
+- [weasyprint](https://weasyprint.org/) *(for PDF output)*
+
+License
+-------
-## License
[MIT](https://opensource.org/licenses/MIT)
+Documentation
+-------------
+
+Documentation and examples are available at
+[domvwt.github.io/esparto/](https://domvwt.github.io/esparto/).
-## Documentation
-Full documentation and examples are available at [domvwt.github.io/esparto/](https://domvwt.github.io/esparto/).
+Contributions, Issues, and Requests
+-----------------------------------
-## Contributions, Issues, and Requests
-All feedback and contributions are welcome - please raise an issue or pull request on [GitHub][GitHub].
+Feedback and contributions are welcome - please raise an issue or pull request
+on [GitHub][GitHub].
+Examples
+--------
-## Examples
Iris Report - [Webpage](https://domvwt.github.io/esparto/examples/iris-report.html) |
[PDF](https://domvwt.github.io/esparto/examples/iris-report.pdf)
-Bokeh and Plotly - [Webpage](https://domvwt.github.io/esparto/examples/interactive-plots.html) |
-[PDF](https://domvwt.github.io/esparto/examples/interactive-plots.pdf)
-
- +
- + [PyPI]: https://pypi.org/project/esparto/ [Conda]: https://anaconda.org/conda-forge/esparto -[Bootstrap]: https://getbootstrap.com/docs/4.6/getting-started/introduction/ +[Bootstrap]: https://getbootstrap.com/ +[Jinja]: https://jinja.palletsprojects.com/ +[Markdown]: https://www.markdownguide.org/ +[Pillow]: https://python-pillow.org/ [Pandas]: https://pandas.pydata.org/ [Matplotlib]: https://matplotlib.org/ -[Bokeh]: https://docs.bokeh.org/en/latest/index.html +[Bokeh]: https://bokeh.org/ [Plotly]: https://plotly.com/ [GitHub]: https://github.com/domvwt/esparto diff --git a/devdocs/classes.png b/devdocs/classes.png index 739874b..a7e34d3 100644 Binary files a/devdocs/classes.png and b/devdocs/classes.png differ diff --git a/docs/01-getting-started/esparto-image-screenshot.png b/docs/01-getting-started/esparto-image-screenshot.png deleted file mode 100644 index ba17312..0000000 Binary files a/docs/01-getting-started/esparto-image-screenshot.png and /dev/null differ diff --git a/docs/01-getting-started/esparto-quickstart-screenshot.png b/docs/01-getting-started/esparto-quickstart-screenshot.png deleted file mode 100644 index 5aaca84..0000000 Binary files a/docs/01-getting-started/esparto-quickstart-screenshot.png and /dev/null differ diff --git a/docs/02-user-guide/quick-start.md b/docs/02-user-guide/quick-start.md index 28e855c..1d55198 100644 --- a/docs/02-user-guide/quick-start.md +++ b/docs/02-user-guide/quick-start.md @@ -1,77 +1,97 @@ # Quick Start ## Create a Page + ```python +import esparto as es + page = es.Page(title="Page Title") -page[0] = "Page Content" +page["Section Title"] += "Some text" +page["Section Title"] += "More text" + page.tree() ``` + ``` -{'Page Title': [{'Section 0': [{'Row 0': [{'Column 0': ['Markdown']}]}]}]} +{'Page Title': [{'Section Title': [{'Row 0': [{'Column 0': ['Markdown']}]}, + {'Row 1': [{'Column 0': ['Markdown']}]}]}]} ``` ## Add Content + ### Define Rows and Columns + ```python -page = es.Page("Page Title") -page["Section One"]["Row One"]["Column One"] = "Some content" -page["Section One"]["Row One"]["Column Two"] = "More content" -page.tree() +page["Section Title"]["Row Title"][0] = "Some content" +page["Section Title"]["Row Title"][1] = "More content" ``` + ``` -{'Page Title': [{'Section One': [{'Row One': [{'Column One': ['Markdown']}, - {'Column Two': ['Markdown']}]}]}]} +{'Page Title': [{'Section Title': [{'Row Title': [{'Column 0': ['Markdown']}, + {'Column 1': ['Markdown']}]}]}]} ``` -### Define multiple Columns as a tuple of dicts +### Define multiple Columns + ```python -page = es.Page("Page Title") -page["Section One"]["Row One"] = ( - {"Column One": "Some content"}, +page["Section Title"]["Row Title"] = ( + {"Column Title": "Some content"}, {"Column Two": "More content"} ) -page.tree() ``` + ``` -{'Page Title': [{'Section One': [{'Row One': [{'Column One': ['Markdown']}, - {'Column Two': ['Markdown']}]}]}]} +{'Page Title': [{'Section Title': [{'Row Title': [{'Column Title': ['Markdown']}, + {'Column Two': ['Markdown']}]}]}]} ``` ## Update Content + ### Access existing content via Indexing or as Attributes + ```python -page["Section One"]["Row One"]["Column One"] = image_01 -page.section_one.row_one.column_two = image_02 -page.section_one.tree() +page["Section Title"]["Row Title"]["Column Title"] = image_01 +page.section_title.row_title.column_two = image_02 ``` + ``` -{'Page Title': [{'Section One': [{'Row One': [{'Column One': ['Image']}, - {'Column Two': ['Image']}]}]}]} +{'Page Title': [{'Section Title': [{'Row Title': [{'Column Title': ['Image']}, + {'Column Two': ['Image']}]}]}]} ``` ## Delete Content + ### Delete the last Column + ```python -del page.section_one.row_one[-1] +del page.section_title.row_title[-1] ``` + ``` -{'Page Title': [{'Section One': [{'Row One': [{'Column One': ['Image']}]}]}]} +{'Page Title': [{'Section Title': [{'Row Title': [{'Column Title': ['Image']}]}]}]} ``` + ### Delete a named Column + ```python -del page.section_one.row_one.column_two +del page.section_title.row_title.column_two page.tree() ``` + ``` -{'Page Title': [{'Section One': [{'Row One': [{'Column One': ['Image']}]}]}]} +{'Page Title': [{'Section Title': [{'Row Title': [{'Column Title': ['Image']}]}]}]} ``` ## Save the Document + ### As a webpage + ```python my_page.save_html("my-esparto-doc.html") ``` + ### As a PDF + ```python my_page.save_pdf("my-esparto-doc.pdf") ``` diff --git a/docs/02-user-guide/tutorial-notebooks.md b/docs/02-user-guide/tutorial-notebooks.md index e79f5f1..3061f2a 100644 --- a/docs/02-user-guide/tutorial-notebooks.md +++ b/docs/02-user-guide/tutorial-notebooks.md @@ -1,58 +1,19 @@ # Tutorial Notebooks -These examples demonstrate recommended ways of working with `esparto`. - - -## Getting Started - -[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/domvwt/esparto/blob/main/docs/examples/getting-started.ipynb) -[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/domvwt/esparto/main?filepath=docs%2Fexamples%2Fgetting-started.ipynb) -[![GitHub](https://img.shields.io/badge/view%20on-GitHub-lightgrey)](https://github.com/domvwt/esparto/blob/main/docs/examples/getting-started.ipynb) - -A guided tour of the `esparto` API. This notebook covers: - -* Working with different Content types -* Layout and formatting -* Page options -* Saving your work - ---- - - ## Data Analysis [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/domvwt/esparto/blob/main/docs/examples/iris-report.ipynb) [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/domvwt/esparto/main?filepath=docs%2Fexamples%2Firis-report.ipynb) [![GitHub](https://img.shields.io/badge/view%20on-GitHub-lightgrey)](https://github.com/domvwt/esparto/blob/main/docs/examples/iris-report.ipynb) -This notebook shows how we can put together a simple data analysis in `esparto`. - -This example covers: +This notebook shows how we can put together a simple data analysis report. * Text content with Markdown formatting -* Including images from files * Converting a Pandas DataFrame to a table -* Adding plots from Matplotlib and Seaborn +* Adding plots from Matplotlib Output: [Webpage](../examples/iris-report.html) | [PDF](../examples/iris-report.pdf) ---- - -## Interactive Plots - -[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/domvwt/esparto/blob/main/docs/examples/interactive-plots.ipynb) -[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/domvwt/esparto/main?filepath=docs%2Fexamples%2Finteractive-plots.ipynb) -[![GitHub](https://img.shields.io/badge/view%20on-GitHub-lightgrey)](https://github.com/domvwt/esparto/blob/main/docs/examples/interactive-plots.ipynb) - -This notebook shows basic examples from interactive plotting libraries: - -* Bokeh -* Plotly - -Output: [Webpage](../examples/interactive-plots.html) | [PDF](../examples/interactive-plots.pdf) - -!!! note - PDF output is not officially supported for `Bokeh` at this time. -- The - - Iris flower - - data set, or Fisher's Iris data set, is a multivariate data set introduced by + +
+ + + ++ The + + Iris flower + + data set, or Fisher’s Iris data set, is a multivariate data set introduced by the British statistician, eugenicist, and biologist Ronald Fisher in his 1936 paper -'The use of multiple measurements in taxonomic problems as an example of linear discriminant analysis'. -It is sometimes called Anderson's Iris data set because Edgar Anderson collected the data to quantify +‘The use of multiple measurements in taxonomic problems as an example of linear discriminant analysis’. +It is sometimes called Anderson’s Iris data set because Edgar Anderson collected the data to quantify the morphologic variation of Iris flowers of three related species. Two of the three species were -collected in the Gaspé Peninsula "all from the same pasture, and picked on the same day and measured at -the same time by the same person with the same apparatus". -
-- The data set consists of 50 samples from each of three species of Iris (Iris setosa, Iris virginica and -Iris versicolor). Four features were measured from each sample: the length and the width of the sepals -and petals, in centimeters. Based on the combination of these four features, Fisher developed a linear -discriminant model to distinguish the species from each other. -
-
-
-
- Text retrieved from
-
- Wikipedia
-
- on 2021-04-05
-
- License:
-
- CC-BY-SA-3.0
-
-
-
-
-
-
-
- Photo of Iris Virginica by Eric Hunt
-
- License:
-
- CC-BY-SA-4.0
-
-
-
-
- sepal_length - | -- sepal_width - | -- petal_length - | -- petal_width - | -- species - | -
---|---|---|---|---|
- 5.8 - | -- 4.0 - | -- 1.2 - | -- 0.2 - | -- setosa - | -
- 5.1 - | -- 2.5 - | -- 3.0 - | -- 1.1 - | -- versicolor - | -
- 6.6 - | -- 3.0 - | -- 4.4 - | -- 1.4 - | -- versicolor - | -
- 5.4 - | -- 3.9 - | -- 1.3 - | -- 0.4 - | -- setosa - | -
- 7.9 - | -- 3.8 - | -- 6.4 - | -- 2.0 - | -- virginica - | -
- 6.3 - | -- 3.3 - | -- 4.7 - | -- 1.6 - | -- versicolor - | -
- 6.9 - | -- 3.1 - | -- 5.1 - | -- 2.3 - | -- virginica - | -
- 5.1 - | -- 3.8 - | -- 1.9 - | -- 0.4 - | -- setosa - | -
- 4.7 - | -- 3.2 - | -- 1.6 - | -- 0.2 - | -- setosa - | -
- 6.9 - | -- 3.2 - | -- 5.7 - | -- 2.3 - | -- virginica - | -
+
+
+ Text retrieved from
+
+ Wikipedia
+
+ on 2021-04-05
+
+ License:
+
+ CC-BY-SA-3.0
+
+
+
+
+
+ | ++ sepal_length + | ++ sepal_width + | ++ petal_length + | ++ petal_width + | ++ species + | +
---|---|---|---|---|---|
+ 14 + | ++ 5.8 + | ++ 4.0 + | ++ 1.2 + | ++ 0.2 + | ++ setosa + | +
+ 98 + | ++ 5.1 + | ++ 2.5 + | ++ 3.0 + | ++ 1.1 + | ++ versicolor + | +
+ 75 + | ++ 6.6 + | ++ 3.0 + | ++ 4.4 + | ++ 1.4 + | ++ versicolor + | +
+ 16 + | ++ 5.4 + | ++ 3.9 + | ++ 1.3 + | ++ 0.4 + | ++ setosa + | +
+ 131 + | ++ 7.9 + | ++ 3.8 + | ++ 6.4 + | ++ 2.0 + | ++ virginica + | +
+ 56 + | ++ 6.3 + | ++ 3.3 + | ++ 4.7 + | ++ 1.6 + | ++ versicolor + | +
+ 141 + | ++ 6.9 + | ++ 3.1 + | ++ 5.1 + | ++ 2.3 + | ++ virginica + | +
+ 44 + | ++ 5.1 + | ++ 3.8 + | ++ 1.9 + | ++ 0.4 + | ++ setosa + | +
+ 29 + | ++ 4.7 + | ++ 3.2 + | ++ 1.6 + | ++ 0.2 + | ++ setosa + | +
+ 120 + | ++ 6.9 + | ++ 3.2 + | ++ 5.7 + | ++ 2.3 + | ++ virginica + | +
\n", + " The\n", + " \n", + " Iris flower\n", + " \n", + " data set, or Fisher’s Iris data set, is a multivariate data set introduced by \n", + "the British statistician, eugenicist, and biologist Ronald Fisher in his 1936 paper \n", + "‘The use of multiple measurements in taxonomic problems as an example of linear discriminant analysis’. \n", + "It is sometimes called Anderson’s Iris data set because Edgar Anderson collected the data to quantify \n", + "the morphologic variation of Iris flowers of three related species. Two of the three species were \n", + "collected in the Gaspé Peninsula “all from the same pasture, and picked on the same day and measured at \n", + "the same time by the same person with the same apparatus”.\n", + "
\n", + "\n", + " The\n", + " \n", + " Iris flower\n", + " \n", + " data set, or Fisher’s Iris data set, is a multivariate data set introduced by \n", + "the British statistician, eugenicist, and biologist Ronald Fisher in his 1936 paper \n", + "‘The use of multiple measurements in taxonomic problems as an example of linear discriminant analysis’. \n", + "It is sometimes called Anderson’s Iris data set because Edgar Anderson collected the data to quantify \n", + "the morphologic variation of Iris flowers of three related species. Two of the three species were \n", + "collected in the Gaspé Peninsula “all from the same pasture, and picked on the same day and measured at \n", + "the same time by the same person with the same apparatus”.\n", + "
\n", + "\n",
+ "\n",
+ "\n",
+ " Text retrieved from\n",
+ " \n",
+ " Wikipedia\n",
+ " \n",
+ " on 2021-04-05\n",
+ "
\n",
+ " License:\n",
+ " \n",
+ " CC-BY-SA-3.0\n",
+ " \n",
+ "
\n",
+ "\n",
+ "\n",
+ "
\n", + " The\n", + " \n", + " Iris flower\n", + " \n", + " data set, or Fisher’s Iris data set, is a multivariate data set introduced by \n", + "the British statistician, eugenicist, and biologist Ronald Fisher in his 1936 paper \n", + "‘The use of multiple measurements in taxonomic problems as an example of linear discriminant analysis’. \n", + "It is sometimes called Anderson’s Iris data set because Edgar Anderson collected the data to quantify \n", + "the morphologic variation of Iris flowers of three related species. Two of the three species were \n", + "collected in the Gaspé Peninsula “all from the same pasture, and picked on the same day and measured at \n", + "the same time by the same person with the same apparatus”.\n", + "
\n", + "\n",
+ "\n",
+ "\n",
+ " Text retrieved from\n",
+ " \n",
+ " Wikipedia\n",
+ " \n",
+ " on 2021-04-05\n",
+ "
\n",
+ " License:\n",
+ " \n",
+ " CC-BY-SA-3.0\n",
+ " \n",
+ "
\n",
+ "\n",
+ "\n",
+ "
\n", + " | \n", + "\n", + " sepal_length\n", + " | \n", + "\n", + " sepal_width\n", + " | \n", + "\n", + " petal_length\n", + " | \n", + "\n", + " petal_width\n", + " | \n", + "\n", + " species\n", + " | \n", + "
---|---|---|---|---|---|
\n", + " 14\n", + " | \n", + "\n", + " 5.8\n", + " | \n", + "\n", + " 4.0\n", + " | \n", + "\n", + " 1.2\n", + " | \n", + "\n", + " 0.2\n", + " | \n", + "\n", + " setosa\n", + " | \n", + "
\n", + " 98\n", + " | \n", + "\n", + " 5.1\n", + " | \n", + "\n", + " 2.5\n", + " | \n", + "\n", + " 3.0\n", + " | \n", + "\n", + " 1.1\n", + " | \n", + "\n", + " versicolor\n", + " | \n", + "
\n", + " 75\n", + " | \n", + "\n", + " 6.6\n", + " | \n", + "\n", + " 3.0\n", + " | \n", + "\n", + " 4.4\n", + " | \n", + "\n", + " 1.4\n", + " | \n", + "\n", + " versicolor\n", + " | \n", + "
\n", + " 16\n", + " | \n", + "\n", + " 5.4\n", + " | \n", + "\n", + " 3.9\n", + " | \n", + "\n", + " 1.3\n", + " | \n", + "\n", + " 0.4\n", + " | \n", + "\n", + " setosa\n", + " | \n", + "
\n", + " 131\n", + " | \n", + "\n", + " 7.9\n", + " | \n", + "\n", + " 3.8\n", + " | \n", + "\n", + " 6.4\n", + " | \n", + "\n", + " 2.0\n", + " | \n", + "\n", + " virginica\n", + " | \n", + "
\n", + " 56\n", + " | \n", + "\n", + " 6.3\n", + " | \n", + "\n", + " 3.3\n", + " | \n", + "\n", + " 4.7\n", + " | \n", + "\n", + " 1.6\n", + " | \n", + "\n", + " versicolor\n", + " | \n", + "
\n", + " 141\n", + " | \n", + "\n", + " 6.9\n", + " | \n", + "\n", + " 3.1\n", + " | \n", + "\n", + " 5.1\n", + " | \n", + "\n", + " 2.3\n", + " | \n", + "\n", + " virginica\n", + " | \n", + "
\n", + " 44\n", + " | \n", + "\n", + " 5.1\n", + " | \n", + "\n", + " 3.8\n", + " | \n", + "\n", + " 1.9\n", + " | \n", + "\n", + " 0.4\n", + " | \n", + "\n", + " setosa\n", + " | \n", + "
\n", + " 29\n", + " | \n", + "\n", + " 4.7\n", + " | \n", + "\n", + " 3.2\n", + " | \n", + "\n", + " 1.6\n", + " | \n", + "\n", + " 0.2\n", + " | \n", + "\n", + " setosa\n", + " | \n", + "
\n", + " 120\n", + " | \n", + "\n", + " 6.9\n", + " | \n", + "\n", + " 3.2\n", + " | \n", + "\n", + " 5.7\n", + " | \n", + "\n", + " 2.3\n", + " | \n", + "\n", + " virginica\n", + " | \n", + "