Skip to content

Commit d5274a2

Browse files
yuxqiuKD-7
andauthored
refactor: refactor visualisations (#56)
* refactor: refactor base classes * ci: update ci filter * refactor: enrich base API * refactor: remove support of list of tuples * refactor: update bar plotter * refactor: add a `set_size_inches` method to `MatplotlibBasePlotter` * refactor: update bubble plotter * refactor: update dot plotter * refactor: update rose pie chart * refactor: update word plotter * refactor: update radar plotter * refactor: update treemap * refactor: update line plotter * style: reformat * refactor: update `_standardise_data` * refactor: update plot * docs: update docs * docs: update docs * docs: update class docs * test: implement visualisations tests * test: update tests * test: update image tests * test: try using scale * test: try increasing tol * test: try increasing tol * build: try fixing plotly and kaleido version * test: update tests * test: use tol to test images * test: update word plotter * test: update word plotter * test: update `file_comparison` * test: update word plotter * test: update font * test: debug font used * test: remove word cloud tests * feat: add a `Range` class * test: add range repr test * refactor: refactor base classes * ci: update ci filter * refactor: enrich base API * refactor: remove support of list of tuples * refactor: update bar plotter * refactor: add a `set_size_inches` method to `MatplotlibBasePlotter` * refactor: update bubble plotter * refactor: update dot plotter * refactor: update rose pie chart * refactor: update word plotter * refactor: update radar plotter * refactor: update treemap * refactor: update line plotter * style: reformat * refactor: update `_standardise_data` * refactor: update plot * docs: update docs * docs: update docs * docs: update class docs * test: implement visualisations tests * test: update tests * test: update image tests * test: try using scale * test: try increasing tol * test: try increasing tol * build: try fixing plotly and kaleido version * test: update tests * test: use tol to test images * test: update word plotter * test: update word plotter * test: update `file_comparison` * test: update word plotter * test: update font * test: debug font used * test: remove word cloud tests * feat: add a `Range` class * test: add range repr test * test: improve test coverage * test: improve treemap tests * fix: typos and warnings * fix: resolve some issues * docs: update docs * docs: update docs * docs: add visualisations doc * fix: add checks for empty knowledge and corresponding regression tests * test: add regression tests for top n * docs: update docs * test: fix pie plotter history and other test * docs: update examples * change rubric header appearance * chore: fix a typo and reformat * docs: update tests * test: update wordcloud dependency requirement * chore: fix typo * revert: revert word plotter change * test: improve coverage * docs: add examples * refactor: remove unnecessary params * docs: fix typos --------- Co-authored-by: KD-7 <[email protected]>
1 parent 22c0741 commit d5274a2

File tree

98 files changed

+2104
-834
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+2104
-834
lines changed

.github/workflows/coverage.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ on:
99
- '**.py'
1010
- '.github/workflows/coverage.yml'
1111
pull_request:
12-
branches:
13-
- main
1412
# filter on files that should trigger this workflow
1513
paths:
1614
- 'pyproject.toml'

.github/workflows/static_analysis.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ on:
99
- '**.py'
1010
- '.github/workflows/static_analysis.yml'
1111
pull_request:
12-
branches:
13-
- main
1412
# filter on files that should trigger this workflow
1513
paths:
1614
- 'pyproject.toml'

.github/workflows/unit_tests.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ on:
99
- '**.py'
1010
- '.github/workflows/unit_tests.yml'
1111
pull_request:
12-
branches:
13-
- main
1412
# filter on files that should trigger this workflow
1513
paths:
1614
- 'pyproject.toml'

docs/_static/custom.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ h1 {
66
overflow-wrap: break-word;
77
}
88

9+
dd p.rubric {
10+
font-size: 1rem;
11+
font-weight: 500;
12+
margin-top: 1rem;
13+
line-height: inherit;
14+
text-transform: uppercase;
15+
}
16+
917
/* End Furo theme overrides */
1018

1119
/* suppress download button and timing at top/bottom of every tutorial */

docs/conf.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
copyright = "2023, TrueLearn"
3232
author = "TrueLearn Team"
3333

34-
# pylint: disable=wrong-import-position
3534
import truelearn
3635

3736
version = truelearn.__version__
@@ -40,16 +39,17 @@
4039
# -- General configuration ---------------------------------------------------
4140
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
4241

43-
extensions = ["sphinx.ext.autodoc",
44-
"sphinx.ext.linkcode",
45-
"sphinx.ext.autosummary",
46-
"sphinx.ext.napoleon",
47-
"sphinx.ext.intersphinx",
48-
"sphinx.ext.doctest",
49-
"sphinx_copybutton",
50-
"sphinx_gallery.gen_gallery",
51-
]
52-
templates_path = ['templates']
42+
extensions = [
43+
"sphinx.ext.autodoc",
44+
"sphinx.ext.linkcode",
45+
"sphinx.ext.napoleon",
46+
"sphinx.ext.intersphinx",
47+
"sphinx.ext.doctest",
48+
"sphinx_copybutton",
49+
"sphinx_gallery.gen_gallery",
50+
"sphinx.ext.autosummary",
51+
]
52+
templates_path = ["templates"]
5353
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
5454

5555
# -- Options for autodoc extension -------------------------------------------
@@ -68,6 +68,7 @@
6868
# Code below from:
6969
# https://github.com/Lasagne/Lasagne/blob/master/docs/conf.py#L114
7070

71+
7172
def linkcode_resolve(domain, info):
7273
"""Determine the URL corresponding to the sourcecode."""
7374

@@ -106,6 +107,13 @@ def find_source():
106107

107108

108109
# -- Gallery configuration ---------------------------------------------------
110+
from plotly.io._sg_scraper import plotly_sg_scraper
111+
112+
image_scrapers = (
113+
"matplotlib",
114+
plotly_sg_scraper,
115+
)
116+
109117
sphinx_gallery_conf = {
110118
"reference_url": {
111119
# The module you locally document uses None
@@ -117,6 +125,7 @@ def find_source():
117125
"remove_config_comments": True,
118126
"show_memory": False,
119127
"show_signature": False,
128+
"image_scrapers": image_scrapers,
120129
}
121130

122131
# -- Options for napoleon extension ------------------------------------------

docs/dev/design_considerations.rst

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ This provides a lot of flexibility for developers as they “are not forced to i
7979

8080
But they have now made some changes to the design. Their ``Classifier`` implementations now inherit a class ``BaseClassifier`` to provide
8181
parameter type checking and implementation of some common methods such as ``__repr__``.
82-
**TrueLearn took inspiration from it and designed our ``BaseClassifier``, type checking and implemented common methods.**
82+
**TrueLearn took inspiration from this in the design of our** ``BaseClassifier``
83+
**which enforces type checking and contains the implementation of some shared methods.**
8384

8485

8586
Project Structure
@@ -91,9 +92,9 @@ At time of writing, the repository includes the following subpackages:
9192
* truelearn/datasets: contains the methods to download and load PEEKDataset.
9293
* truelearn/learning: contains the implementation of all the classifiers.
9394
* truelearn/models: contains the definitions of event model and learner model.
94-
* truelearn/preprocessing: contains the preprocessing utilities, such as wikifier.
95+
* truelearn/preprocessing: contains the preprocessing utilities, such as Wikifier.
9596
* truelearn/tests: contains all the tests for TrueLearn library.
96-
* truelearn/utils: contains two utility packages, ``metrics`` (contains scoring functions) and ``visualization`` (contain different visualizations).
97+
* truelearn/utils: contains two utility packages, ``metrics`` (contains scoring functions) and ``visualisations``.
9798

9899

99100
truelearn.models
@@ -142,8 +143,8 @@ This package contains all the tests for TrueLearn.
142143
* test_datasets: contains the tests for ``truelearn.datasets``.
143144
* test_learning: contains the tests for ``truelearn.learning``.
144145
* test_models: contains the tests for ``truelearn.models``.
145-
* test_datasets: contains the tests for ``truelearn.datasets``.
146-
* test_datasets: contains the tests for ``truelearn.datasets``.
147-
* test_datasets: contains the tests for ``truelearn.datasets``.
146+
* test_preprocessing: contains the tests for ``truelearn.preprocessing``.
147+
* test_utils_metrics: contains the tests for ``truelearn.utils.metrics``.
148+
* test_utils_visualisations: contains the tests for ``truelearn.utils.visualisations``.
148149

149150
To learn how to run the tests and add more tests to TrueLearn, please refer to :ref:`testing`.

docs/dev/documentation.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ in build page of Read the Docs.
1212
.. image:: ../images/read-the-docs-view-docs.jpeg
1313

1414

15-
Building the documentation
16-
--------------------------
15+
Building the documentation locally
16+
----------------------------------
1717

1818
To build the documentation locally, run the following command from the root of the
1919
repository::

docs/dev/testing.rst

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ Please see the `prospector documentation`_ for more output options.
7878

7979
Adding New Tests
8080
----------------
81+
82+
General Strategy
83+
""""""""""""""""
8184
To add a new test, you need to add the test case to the corresponding test in ``truelearn/tests``.
8285

8386
For example, if you want to add a new test for ``KnowledgeClassifier``, you can add the test case to ``truelearn/tests/test_learning.py``.
@@ -92,3 +95,40 @@ Also, based on the ``pytest`` rules, you need to make sure that the names of you
9295

9396
def test_xxx():
9497
...
98+
99+
100+
Writing a visualisation test
101+
"""""""""""""""""""""""""""""
102+
103+
Writing a test for a visualisation is more difficult than ordinary unit tests.
104+
In these tests, we typically want to test that our generated file is identical or similar to a baseline file,
105+
which we will refer to as a "file comparison test".
106+
107+
To write a file comparison test, you only need to add a simple class decorator to your class.
108+
109+
For example, this is a simple file comparison test inside ``truelearn/tests/test_utils_visualisations.py``::
110+
111+
@file_comparison(plotter_type="plotly")
112+
class TestBarPlotter:
113+
def test_default(self, resources):
114+
plotter = visualisations.BarPlotter()
115+
plotter.plot(resources[0])
116+
return plotter
117+
118+
def test_history(self, resources):
119+
plotter = visualisations.BarPlotter()
120+
plotter.plot(resources[0], history=True)
121+
return plotter
122+
123+
The first time this test is run, there will be no baseline image to compare against, so the test will fail.
124+
But you will find that a directory called ``tests`` has been generated in your current working directory.
125+
Inside it, there will be a directory whose name is lowercase for the test class name where you can find all of the generated baseline files (i.e. ``testbarplotter`` for the example above).
126+
Your next step is copy this directory to ``truelearn/tests/baseline_files/``.
127+
Then, when you run the test again, if the file you generated matches the baseline, your test will pass.
128+
129+
Due to the way that file comparison tests work, all visualisation tests must be grouped into classes.
130+
We recommend that you name all tests that make use of file comparison ``TestXXXPlotter``, where ``XXXPlotter`` is the plotter you want to test.
131+
If you do not use file comparisons, you can simply create ``TestXXXPlotterNormal`` and
132+
place all tests that do not use file comparisons in this class.
133+
134+
You can see the documentation of ``file_comparison`` for additional information about its use.

docs/modules/api_reference.rst

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,12 @@ Classes
164164
:toctree: generated/
165165
:template: class.rst
166166

167-
Functions
168-
---------
169-
.. currentmodule:: truelearn
170-
171-
.. autosummary::
172-
:toctree: generated/
173-
:template: function.rst
167+
utils.visualisations.LinePlotter
168+
utils.visualisations.PiePlotter
169+
utils.visualisations.RosePlotter
170+
utils.visualisations.BarPlotter
171+
utils.visualisations.DotPlotter
172+
utils.visualisations.BubblePlotter
173+
utils.visualisations.WordPlotter
174+
utils.visualisations.RadarPlotter
175+
utils.visualisations.TreePlotter

examples/plot_interest_radar.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# noqa
2+
"""
3+
RadarPlotter Example
4+
====================
5+
6+
This example shows how to use the ``RadarPlotter`` class
7+
to generate a radar plot to study the mean and variance
8+
of the learner's knowledge.
9+
10+
In this example, we use the ``InterestClassifier`` to build
11+
a representation of the learner's interest. You could also use
12+
other classifiers like ``KnowledgeClassifier`` or ``NoveltyClassifier``
13+
to build a representation of learner's knowledge.
14+
"""
15+
from truelearn import learning, datasets
16+
from truelearn.utils import visualisations
17+
18+
import plotly.io as pio
19+
20+
data, _, _ = datasets.load_peek_dataset(test_limit=0)
21+
22+
# select a learner from data
23+
_, learning_events = data[12]
24+
25+
classifier = learning.InterestClassifier()
26+
for event, label in learning_events:
27+
classifier.fit(event, label)
28+
29+
plotter = visualisations.RadarPlotter()
30+
31+
# you can optionally set a title
32+
plotter.title("Mean and variance of interest in different topics.")
33+
34+
# we could select topics we care via `topics`
35+
plotter.plot(
36+
classifier.get_learner_model().knowledge,
37+
topics=[
38+
"Expected value",
39+
"Probability",
40+
"Sampling (statistics)",
41+
"Calculus of variations",
42+
"Dimension",
43+
"Computer virus",
44+
],
45+
)
46+
47+
# you can also use plotter.show() here
48+
# which is a shorthand for calling pio
49+
pio.show(plotter.figure)

0 commit comments

Comments
 (0)