├── d3heatmap
├── d3js
│ ├── __init__.py
│ ├── d3.v4.js
│ ├── d3.v2.min.js
│ ├── d3script.html
│ ├── d3.scale.chromatic.v1.min.js
│ └── d3heatmap.html
├── __init__.py
├── examples.py
└── d3heatmap.py
├── docs
├── example
│ ├── __init__.py
│ ├── d3.v2.min.js
│ ├── d3heatmap.html
│ └── data.json
└── figs
│ ├── example_1.png
│ ├── example_2.png
│ ├── example_3.png
│ ├── example_4.png
│ ├── example_5.png
│ └── example_6.png
├── requirements-dev.txt
├── tests
└── test_d3heatmap.py
├── MANIFEST.in
├── requirements.txt
├── make_clean.sh
├── CITATION.cff
├── make_sphinx_and_commit.sh
├── .github
└── FUNDING.yml
├── LICENSE
├── setup.py
├── .gitignore
├── notebooks
└── d3heatmap.ipynb
└── README.md
/d3heatmap/d3js/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/example/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | sphinx_rtd_theme
2 | rst2pdf
3 | pip install spyder-kernels
4 |
--------------------------------------------------------------------------------
/tests/test_d3heatmap.py:
--------------------------------------------------------------------------------
1 | import d3heatmap as d3heatmap
2 |
3 | def test_plot():
4 | pass
--------------------------------------------------------------------------------
/d3heatmap/d3js/d3.v4.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdogant/d3heatmap/HEAD/d3heatmap/d3js/d3.v4.js
--------------------------------------------------------------------------------
/docs/figs/example_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdogant/d3heatmap/HEAD/docs/figs/example_1.png
--------------------------------------------------------------------------------
/docs/figs/example_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdogant/d3heatmap/HEAD/docs/figs/example_2.png
--------------------------------------------------------------------------------
/docs/figs/example_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdogant/d3heatmap/HEAD/docs/figs/example_3.png
--------------------------------------------------------------------------------
/docs/figs/example_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdogant/d3heatmap/HEAD/docs/figs/example_4.png
--------------------------------------------------------------------------------
/docs/figs/example_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdogant/d3heatmap/HEAD/docs/figs/example_5.png
--------------------------------------------------------------------------------
/docs/figs/example_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdogant/d3heatmap/HEAD/docs/figs/example_6.png
--------------------------------------------------------------------------------
/d3heatmap/d3js/d3.v2.min.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdogant/d3heatmap/HEAD/d3heatmap/d3js/d3.v2.min.js
--------------------------------------------------------------------------------
/docs/example/d3.v2.min.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdogant/d3heatmap/HEAD/docs/example/d3.v2.min.js
--------------------------------------------------------------------------------
/docs/example/d3heatmap.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erdogant/d3heatmap/HEAD/docs/example/d3heatmap.html
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include d3heatmap/d3js/*.js
2 | include d3heatmap/d3js/*.css
3 | include d3heatmap/d3js/*.html
4 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | #conda create -n env_d3heatmap python=3.6
2 | #conda activate env_d3heatmap
3 | #conda install spyder
4 |
5 | wget
6 | matplotlib
7 | numpy
8 | pandas
9 | tqdm
10 |
--------------------------------------------------------------------------------
/make_clean.sh:
--------------------------------------------------------------------------------
1 | echo "Cleaning previous builds first.."
2 | rm -rf dist
3 | rm -rf build
4 | rm -rf d3heatmap.egg-info
5 | rm -rf __pycache__
6 | rm -rf d3heatmap/__pycache__
7 | rm -rf d3heatmap/utils/__pycache__
8 | rm -rf .pytest_cache
9 | rm -rf .pylint.d
10 | rm -rf d3heatmap/data/*.zip
11 | rm -rf d3heatmap/data/*.csv
12 | rm -rf *.js
13 | rm -rf *.html
14 | rm -rf *.css
15 | rm -rf *.dot
16 | rm -rf *.png
17 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | # YAML 1.2
2 | ---
3 | authors:
4 | -
5 | family-names: Taskesen
6 | given-names: Erdogan
7 | orcid: "https://orcid.org/0000-0002-3430-9618"
8 | cff-version: "1.1.0"
9 | date-released: 2019-12-28
10 | keywords:
11 | - "heatmap"
12 | - "interactive"
13 | - "clustering"
14 | - "d3js"
15 | - "python"
16 | license: "MIT"
17 | message: "If you use this software, please cite it using these metadata."
18 | repository-code: "https://github.com/erdogant/d3heatmap"
19 | title: "Interactive and standalone heatmaps (d3heatmap)"
20 | version: "0.1.7"
21 | ...
22 |
--------------------------------------------------------------------------------
/make_sphinx_and_commit.sh:
--------------------------------------------------------------------------------
1 | echo "$PWD"
2 | cd docs
3 | echo "$PWD"
4 |
5 | echo "Cleaning previous builds first.."
6 | make.bat clean
7 |
8 | echo "Building new html.."
9 | make.bat html
10 |
11 | cd ..
12 |
13 | echo "Press [q]uit to Quit and [Enter] key to: git add -> commit -> push."
14 | read VAR
15 |
16 |
17 | if [[ $VAR = "" ]]; then
18 | read -p "Ready?"
19 | git pull
20 | git add .
21 | git commit -m "update sphinx pages"
22 | git push
23 |
24 | read -p "All done! Press [Enter] to close this window."
25 | exit
26 | fi
27 |
28 |
29 | if [ $VAR == "q" ]; then
30 | echo Quit!
31 | fi
32 |
33 | read -p "Press [Enter] to close this window."
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [erdogant]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: #
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Erdogan Taskesen
4 | d3heatmap - Python package
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/d3heatmap/__init__.py:
--------------------------------------------------------------------------------
1 | from d3heatmap import d3heatmap
2 |
3 |
4 | __author__ = 'Erdogan Tasksen'
5 | __email__ = 'erdogant@gmail.com'
6 | __version__ = '0.2.3'
7 |
8 | # module level doc-string
9 | __doc__ = """
10 | d3heatmap
11 | =====================================================================
12 |
13 | Description
14 | -----------
15 | d3heatmap is a Python package to create interactive heatmaps based on d3js.
16 |
17 | Example
18 | -------
19 | >>> # Load library
20 | >>> from d3heatmap import d3heatmap as d3
21 | >>>
22 | >>> # Example 1:
23 | >>> df = d3.import_example()
24 | >>> # Create heatmap
25 | >>> paths = d3.heatmap(df, vmax=1)
26 | >>>
27 | >>> # Example 2:
28 | >>> df = d3.import_example(size=(12,20))
29 | >>> # Create heatmap
30 | >>> paths = d3.matrix(df)
31 | >>>
32 | >>> # Example 3:
33 | >>> # The dataframe contains more columns then rows. Adjust the size and color differently.
34 | >>> paths = d3.matrix(df, fontsize=10, title='Hooray!', description='d3 matrix is created using https://github.com/erdogant/d3heatmap.', path='c:/temp/example/d3_matrix.html', width=600, height=300, cmap='interpolateGreens', vmin=1)
35 | >>>
36 |
37 | References
38 | ----------
39 | * https://github.com/erdogant/d3heatmap
40 | * https://d3-graph-gallery.com
41 | * https://https://d3js.org/
42 | """
43 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 | import re
3 |
4 | # versioning ------------
5 | VERSIONFILE="d3heatmap/__init__.py"
6 | getversion = re.search( r"^__version__ = ['\"]([^'\"]*)['\"]", open(VERSIONFILE, "rt").read(), re.M)
7 | if getversion:
8 | new_version = getversion.group(1)
9 | else:
10 | raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))
11 |
12 | # Setup ------------
13 | with open("README.md", "r") as fh:
14 | long_description = fh.read()
15 | setuptools.setup(
16 | install_requires=['ismember','clusteval', 'numpy', 'pandas'],
17 | python_requires='>=3',
18 | name='d3heatmap',
19 | version=new_version,
20 | author="Erdogan Taskesen",
21 | author_email="erdogant@gmail.com",
22 | description="Python package to create interactive heatmap based on d3js.",
23 | long_description=long_description,
24 | long_description_content_type="text/markdown",
25 | url="https://github.com/erdogant/d3heatmap",
26 | download_url = 'https://github.com/erdogant/d3heatmap/archive/' + new_version+'.tar.gz',
27 | packages=setuptools.find_packages(), # Searches throughout all dirs for files to include
28 | include_package_data=True, # Must be true to include files depicted in MANIFEST.in
29 | license_files=["LICENSE"],
30 | classifiers=[
31 | "Programming Language :: Python :: 3",
32 | "License :: OSI Approved :: MIT License",
33 | "Operating System :: OS Independent",
34 | ],
35 | )
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | d3heatmap/data/
10 |
11 | # Distribution / packaging
12 | .pylint.*
13 | .Python
14 | build/
15 | develop-eggs/
16 | dist/
17 | downloads/
18 | eggs/
19 | .eggs/
20 | lib/
21 | lib64/
22 | parts/
23 | sdist/
24 | var/
25 | wheels/
26 | pip-wheel-metadata/
27 | share/python-wheels/
28 | *.egg-info/
29 | .installed.cfg
30 | *.egg
31 | MANIFEST
32 |
33 | # PyInstaller
34 | # Usually these files are written by a python script from a template
35 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
36 | *.manifest
37 | *.spec
38 |
39 | # Installer logs
40 | pip-log.txt
41 | pip-delete-this-directory.txt
42 |
43 | # Unit test / coverage reports
44 | htmlcov/
45 | .tox/
46 | .nox/
47 | .coverage
48 | .coverage.*
49 | .cache
50 | nosetests.xml
51 | coverage.xml
52 | *.cover
53 | *.py,cover
54 | .hypothesis/
55 | .pytest_cache/
56 |
57 | # Translations
58 | *.mo
59 | *.pot
60 |
61 | # Django stuff:
62 | *.log
63 | local_settings.py
64 | db.sqlite3
65 | db.sqlite3-journal
66 |
67 | # Flask stuff:
68 | instance/
69 | .webassets-cache
70 |
71 | # Scrapy stuff:
72 | .scrapy
73 |
74 | # Sphinx documentation
75 | docs/_build/
76 |
77 | # PyBuilder
78 | target/
79 |
80 | # Jupyter Notebook
81 | .ipynb_checkpoints
82 |
83 | # IPython
84 | profile_default/
85 | ipython_config.py
86 |
87 | # pyenv
88 | .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98 | __pypackages__/
99 |
100 | # Celery stuff
101 | celerybeat-schedule
102 | celerybeat.pid
103 |
104 | # SageMath parsed files
105 | *.sage.py
106 |
107 | # Environments
108 | .env
109 | .venv
110 | env/
111 | venv/
112 | ENV/
113 | env.bak/
114 | venv.bak/
115 |
116 | # Spyder project settings
117 | .spyderproject
118 | .spyproject
119 |
120 | # Rope project settings
121 | .ropeproject
122 |
123 | # mkdocs documentation
124 | /site
125 |
126 | # mypy
127 | .mypy_cache/
128 | .dmypy.json
129 | dmypy.json
130 |
131 | # Pyre type checker
132 | .pyre/
133 | .pylint.*
--------------------------------------------------------------------------------
/notebooks/d3heatmap.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "d3heatmap.ipynb",
7 | "provenance": []
8 | },
9 | "kernelspec": {
10 | "name": "python3",
11 | "display_name": "Python 3"
12 | }
13 | },
14 | "cells": [
15 | {
16 | "cell_type": "markdown",
17 | "metadata": {
18 | "id": "bn1shPtj5B1K"
19 | },
20 | "source": [
21 | "**d3heatmap** is a Python package to create *interactive heatmaps* based on d3js. \n",
22 | "\n",
23 | "The **aim** of d3heatmap is to create interactive heatmaps that can be used stand-alone and visual attractive. This library does **not** require you any additional installation, downloads or setting paths to your systems environments. You just need python and this library. All other is taken care off. There are two main functions to create a heatmap matrix and heatmap and there are some differences between the two.\n",
24 | "\n",
25 | "More information can be found here:\n",
26 | "\n",
27 | "* [Github](https://github.com/erdogant/d3heatmap)\n",
28 | "\n"
29 | ]
30 | },
31 | {
32 | "cell_type": "code",
33 | "metadata": {
34 | "id": "bLW2rBTm5A_Y"
35 | },
36 | "source": [
37 | "!pip install -U d3heatmap"
38 | ],
39 | "execution_count": null,
40 | "outputs": []
41 | },
42 | {
43 | "cell_type": "code",
44 | "metadata": {
45 | "id": "rsF9wTuj6yEV"
46 | },
47 | "source": [
48 | "import d3heatmap\n",
49 | "print(d3heatmap.__version__)"
50 | ],
51 | "execution_count": null,
52 | "outputs": []
53 | },
54 | {
55 | "cell_type": "code",
56 | "metadata": {
57 | "id": "-b-D9mmG5y9v"
58 | },
59 | "source": [
60 | "# Load library\n",
61 | "from d3heatmap import d3heatmap as d3"
62 | ],
63 | "execution_count": null,
64 | "outputs": []
65 | },
66 | {
67 | "cell_type": "code",
68 | "metadata": {
69 | "id": "lNB2xz-t5oyP"
70 | },
71 | "source": [
72 | "# Load some random data\n",
73 | "df = d3.import_example()"
74 | ],
75 | "execution_count": null,
76 | "outputs": []
77 | },
78 | {
79 | "cell_type": "code",
80 | "metadata": {
81 | "id": "8ppPQe235vpj"
82 | },
83 | "source": [
84 | "# Create heatmap. Note that this is not allowed on colab as it requires to write the html file to disk.\n",
85 | "paths = results = d3.heatmap(df, showfig=False)"
86 | ],
87 | "execution_count": null,
88 | "outputs": []
89 | },
90 | {
91 | "cell_type": "code",
92 | "metadata": {
93 | "id": "ofV4mvHU63pd"
94 | },
95 | "source": [
96 | ""
97 | ],
98 | "execution_count": null,
99 | "outputs": []
100 | }
101 | ]
102 | }
--------------------------------------------------------------------------------
/d3heatmap/examples.py:
--------------------------------------------------------------------------------
1 | # %%
2 | # import d3heatmap as d3
3 | # print(dir(d3))
4 | # print(d3.__version__)
5 |
6 | # %%
7 | import pandas as pd
8 | import numpy as np
9 | from d3heatmap import d3heatmap as d3
10 |
11 | # %%
12 | # Import example
13 | df = d3.import_example()
14 | # Create interactive heatmap
15 | results = d3.heatmap(df, vmax=1, path='c:/temp/d3_matrix.html', color=None)
16 |
17 |
18 | # %% Create heatmap without clustering
19 | df = d3.import_example(size=(6, 20))
20 |
21 | # Create matrix using default settings
22 | # d3.matrix(df)
23 |
24 | # The dataframe contains more columns then rows. Adjust the size and color differently.
25 | d3.matrix(df, fontsize=10, title='Hooray!', description='d3 matrix is created using https://github.com/erdogant/d3heatmap.', path='c:/temp/d3_matrix.html', width=600, height=300, cmap='interpolateGreens', vmin=1, showfig=True)
26 |
27 |
28 | # %% Create heatmap with clustering
29 |
30 | # Import example
31 | df = d3.import_example()
32 |
33 | # Create interactive heatmap
34 | results = d3.heatmap(df, vmax=1, path='c:/temp/d3_matrix.html', color=None)
35 |
36 | # Create heatmap with some user-defined settings
37 | # results = d3.heatmap(df, vmax=1, width=800, height=800, path='c:/temp/example/d3_heatmap.html', title='Created in d3heatmap', description='d3 heatmap is created using https://github.com/erdogant/d3heatmap. This heatmap is a stand-alone application!')
38 |
39 |
40 | # %% Plot same adjacency matrix using heatmap and matrix
41 | df = d3.import_example()
42 | results = d3.heatmap(df, vmax=1, title='d3heatmap with the heatmap function.')
43 | results = d3.matrix(df, title='d3heatmap with the matrix function.', cmap='interpolateGreens', path='c:/temp/matrix.html')
44 |
45 | # %% Several examples
46 | df = pd.DataFrame(np.random.randint(0, 10, size=(7, 52)))
47 |
48 | d3.matrix(df, fontsize=10, title='Hooray!', description='Heatmap in d3js using python!', path='d3heatmap_example_1.html', height=200, width=750, cmap='interpolateGreens')
49 |
50 | # Change min-max range
51 | d3.matrix(df, fontsize=10, title='Hooray!', description='Heatmap in d3js using python!', path='d3heatmap_example_2.html', height=200, width=750, cmap='interpolateGreens', vmin=8, vmax=10)
52 |
53 | # Scaling
54 | d3.matrix(df, fontsize=10, title='Hooray!', description='Heatmap in d3js using python!', path='d3heatmap_example_3.html', height=200, width=750, cmap='interpolateGreens', scale=True, vmin=80, vmax=100)
55 |
56 | # Change colormap
57 | d3.matrix(df, fontsize=10, title='Hooray!', description='Heatmap in d3js using python!', path='d3heatmap_example_4.html', height=200, width=750, cmap='interpolateGreens', scale=True)
58 |
59 | # Set defaults
60 | d3.matrix(df, fontsize=10, title='Hooray!', description='Heatmap in d3js using python!', path='d3heatmap_example_5.html', height=200, width=750, cmap='interpolateGreens', scale=False, vmin=None, vmax=None)
61 |
62 | # Change stroke color
63 | d3.matrix(df, fontsize=10, title='Hooray!', description='Heatmap in d3js using python!', path='d3heatmap_example_6.html', height=200, width=750, cmap='interpolateGreens', scale=False, stroke='black')
64 |
65 | # Change several parameters
66 | d3.matrix(df, fontsize=10, title='D3Heatmap', description='Heatmap in d3js using python!', path='d3heatmap_example_7.html', height=200, width=750, cmap='interpolateGreens', scale=False, stroke='red', vmin=None, vmax=None)
67 |
68 | # %%
--------------------------------------------------------------------------------
/d3heatmap/d3js/d3script.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## This library is since 18-01-2023 fully implemented in [D3Blocks](https://d3blocks.github.io/d3blocks/pages/html/Heatmap.html). This repo will be froozen at v0.2.3 and not updated anymore. Please use heatmap in D3Blocks for updates and further support.
2 |
3 | # d3heatmap
4 |
5 | [](http://www.repostatus.org/#Moved)
6 | [](https://img.shields.io/pypi/pyversions/d3heatmap)
7 | [](https://pypi.org/project/d3heatmap/)
8 | [](https://d3blocks.github.io/d3blocks/pages/html/Heatmap.html)
9 | [](https://github.com/erdogant/d3heatmap/)
10 | [](https://pepy.tech/project/d3heatmap)
11 | [](https://pepy.tech/project/d3heatmap)
12 | [](https://github.com/erdogant/d3heatmap/blob/master/LICENSE)
13 | [](https://github.com/erdogant/d3heatmap/network)
14 | [](https://github.com/erdogant/d3heatmap/issues)
15 | [](https://zenodo.org/badge/latestdoi/298880904)
16 | [](https://towardsdatascience.com/d3blocks-the-python-library-to-create-interactive-and-standalone-d3js-charts-3dda98ce97d4)
17 | [](https://d3blocks.github.io/d3blocks/pages/html/Documentation.html)
18 |
19 |
20 |
21 |
22 | ``d3heatmap`` is a Python package to create interactive heatmaps based on d3js.
23 | * The **aim** of d3heatmap is to create interactive heatmaps that can be used stand-alone and being visual attractive.
24 | * This library does not require any additional installation of javascript, or downloads or setting paths to your systems environments. You just need python and pip install this library. There are two main functions to create a heatmap and there are some differences between the two. Read below for more details. Have fun!
25 |
26 |
27 | ```
28 | pip install d3blocks
29 |
30 | # Import
31 | from d3blocks import D3Blocks
32 |
33 | # Initialize
34 | d3 = D3Blocks()
35 |
36 | # Load example data
37 | df = d3.import_example('stormofswords')
38 | df = d3.vec2adjmat(df['source'], df['target'], weight=df['weight'], symmetric=True)
39 |
40 | # Plot
41 | d3.heatmap(df)
42 | ```
43 |
44 |
45 | ### Functionalities
46 |
47 | ``d3heatmap.matrix``
48 | * Allows none symetric adjacency matrices.
49 | * Colormap can be changed.
50 | * No clustering.
51 | * round-ish elements.
52 |
53 | ``d3heatmap.heatmap``
54 | * Allows Clustering.
55 | * Colormap is fixed.
56 | * Advanced cluster coloring. Clusters are colored and within each cluster the color is incremental based on the value.
57 | * Adjacency matrix must be symetric.
58 |
59 | #
60 | **Star the [D3Blocks](https://d3blocks.github.io/d3blocks/pages/html/Heatmap.html) repo if you like it! ⭐️**
61 | #
62 |
63 |
64 | #### Installation
65 | ```
66 | pip install d3heatmap
67 | ```
68 |
69 | * Alternatively, install d3heatmap from the GitHub source:
70 | ```bash
71 | git clone https://github.com/erdogant/d3heatmap.git
72 | cd d3heatmap
73 | pip install -U .
74 | ```
75 |
76 | #### Import d3heatmap
77 |
78 | ```python
79 | from d3heatmap import d3heatmap as d3
80 | ```
81 |
82 | #### Example 1: plot using the heatmap function
83 |
84 | ```python
85 | df = d3.import_example()
86 | # Create heatmap
87 | paths = results = d3.heatmap(df)
88 | ```
89 |
90 | Klik on the figure for the interactive example.
91 |
92 |
93 |
94 |
95 |
96 |
97 | #### Example 2: plot using the matrix function
98 |
99 | ```python
100 | df = d3.import_example(size=(6,20))
101 | # Create heatmap
102 | paths = d3.matrix(df)
103 | ```
104 |
105 |
106 |
107 |
108 |
109 |
110 | #### Example 3: plot using the matrix function
111 |
112 | ```python
113 | # The dataframe contains more columns then rows. Adjust the size and color differently.
114 | df = d3.import_example(size=(6,20))
115 | # Create heatmap
116 | paths = d3.matrix(df, fontsize=10, title='Hooray!', description='d3 matrix is created using https://github.com/erdogant/d3heatmap.', path='c:/temp/example/d3_matrix.html', width=600, height=300, cmap='interpolateGreens', vmin=1)
117 | ```
118 |
119 |
120 |
121 |
122 |
123 |
124 | #### Example 4: Matrix with parameters changed:
125 |
126 | ```python
127 | # The dataframe contains more columns then rows. Adjust the size and color differently.
128 | df = d3.import_example(size=(6,20))
129 | # Create heatmap
130 | paths = d3.matrix(df, fontsize=10, title='Hooray!', description='d3 matrix is created using https://github.com/erdogant/d3heatmap.', path='c:/temp/example/d3_matrix.html', width=600, height=300, cmap='interpolateGreens', vmin=1)
131 | ```
132 |
133 |
134 |
135 |
136 |
137 |
138 | #### Example 4: Comparison heatmap vs matrix:
139 | There are quit some differences between the ``heatmap`` vs ``matrix`` functionality.
140 |
141 | ```python
142 | df = d3.import_example()
143 | results = d3.heatmap(df, title='d3heatmap with the heatmap function.', path='heatmap.html')
144 | results = d3.matrix(df, title='d3heatmap with the matrix function.', cmap='interpolatePRGn', path='matrix.html', width=700, height=700)
145 | ```
146 |
147 |
148 |
149 |
150 |
151 |
152 | #### Citation
153 | Please cite d3heatmap in your publications if this is useful for your research. See right column for citation information.
154 |
155 | #### References
156 | * https://github.com/erdogant/d3heatmap
157 | * https://d3-graph-gallery.com
158 | * https://https://d3js.org/
159 |
160 | ### Maintainer
161 | * Erdogan Taskesen, github: [erdogant](https://github.com/erdogant)
162 | * This work is created and maintained in my free time. If you wish to buy me a Coffee for this work, it is very appreciated.
163 | * Contributions are welcome.
164 | * Star it if you like it!
165 |
--------------------------------------------------------------------------------
/docs/example/data.json:
--------------------------------------------------------------------------------
1 | {"nodes":
2 | [
3 | {"name":"Myriel","group":1},
4 | {"name":"Napoleon","group":1},
5 | {"name":"Mlle.Baptistine","group":1},
6 | {"name":"Mme.Magloire","group":1},
7 | {"name":"CountessdeLo","group":1},
8 | {"name":"Geborand","group":1},
9 | {"name":"Champtercier","group":1},
10 | {"name":"Cravatte","group":1},
11 | {"name":"Count","group":1},
12 | {"name":"OldMan","group":1},
13 | {"name":"Labarre","group":2},
14 | {"name":"Valjean","group":2},
15 | {"name":"Marguerite","group":3},
16 | {"name":"Mme.deR","group":2},
17 | {"name":"Isabeau","group":2},
18 | {"name":"Gervais","group":2},
19 | {"name":"Tholomyes","group":3},
20 | {"name":"Listolier","group":3},
21 | {"name":"Fameuil","group":3},
22 | {"name":"Blacheville","group":3},
23 | {"name":"Favourite","group":3},
24 | {"name":"Dahlia","group":3},
25 | {"name":"Zephine","group":3},
26 | {"name":"Fantine","group":3},
27 | {"name":"Mme.Thenardier","group":4},
28 | {"name":"Thenardier","group":4},
29 | {"name":"Cosette","group":5},
30 | {"name":"Javert","group":4},
31 | {"name":"Fauchelevent","group":0},
32 | {"name":"Bamatabois","group":2},
33 | {"name":"Perpetue","group":3},
34 | {"name":"Simplice","group":2},
35 | {"name":"Scaufflaire","group":2},
36 | {"name":"Woman1","group":2},
37 | {"name":"Judge","group":2},
38 | {"name":"Champmathieu","group":2},
39 | {"name":"Brevet","group":2},
40 | {"name":"Chenildieu","group":2},
41 | {"name":"Cochepaille","group":2},
42 | {"name":"Pontmercy","group":4},
43 | {"name":"Boulatruelle","group":6},
44 | {"name":"Eponine","group":4},
45 | {"name":"Anzelma","group":4},
46 | {"name":"Woman2","group":5},
47 | {"name":"MotherInnocent","group":0},
48 | {"name":"Gribier","group":0},
49 | {"name":"Jondrette","group":7},
50 | {"name":"Mme.Burgon","group":7},
51 | {"name":"Gavroche","group":8},
52 | {"name":"Gillenormand","group":5},
53 | {"name":"Magnon","group":5},
54 | {"name":"Mlle.Gillenormand","group":5},
55 | {"name":"Mme.Pontmercy","group":5},
56 | {"name":"Mlle.Vaubois","group":5},
57 | {"name":"Lt.Gillenormand","group":5},
58 | {"name":"Marius","group":8},
59 | {"name":"BaronessT","group":5},
60 | {"name":"Mabeuf","group":8},
61 | {"name":"Enjolras","group":8},
62 | {"name":"Combeferre","group":8},
63 | {"name":"Prouvaire","group":8},
64 | {"name":"Feuilly","group":8},
65 | {"name":"Courfeyrac","group":8},
66 | {"name":"Bahorel","group":8},
67 | {"name":"Bossuet","group":8},
68 | {"name":"Joly","group":8},
69 | {"name":"Grantaire","group":8},
70 | {"name":"MotherPlutarch","group":9},
71 | {"name":"Gueulemer","group":4},
72 | {"name":"Babet","group":4},
73 | {"name":"Claquesous","group":4},
74 | {"name":"Montparnasse","group":4},
75 | {"name":"Toussaint","group":5},
76 | {"name":"Child1","group":10},
77 | {"name":"Child2","group":10},
78 | {"name":"Brujon","group":4},
79 | {"name":"Mme.Hucheloup","group":8}
80 | ],
81 | "links":
82 | [
83 | {"source":1,"target":0,"value":1},
84 | {"source":2,"target":0,"value":8},
85 | {"source":3,"target":0,"value":10},
86 | {"source":3,"target":2,"value":6},
87 | {"source":4,"target":0,"value":1},
88 | {"source":5,"target":0,"value":1},
89 | {"source":6,"target":0,"value":1},
90 | {"source":7,"target":0,"value":1},
91 | {"source":8,"target":0,"value":2},
92 | {"source":9,"target":0,"value":1},
93 | {"source":11,"target":10,"value":1},
94 | {"source":11,"target":3,"value":3},
95 | {"source":11,"target":2,"value":3},
96 | {"source":11,"target":0,"value":5},
97 | {"source":12,"target":11,"value":1},
98 | {"source":13,"target":11,"value":1},
99 | {"source":14,"target":11,"value":1},
100 | {"source":15,"target":11,"value":1},
101 | {"source":17,"target":16,"value":4},
102 | {"source":18,"target":16,"value":4},
103 | {"source":18,"target":17,"value":4},
104 | {"source":19,"target":16,"value":4},
105 | {"source":19,"target":17,"value":4},
106 | {"source":19,"target":18,"value":4},
107 | {"source":20,"target":16,"value":3},
108 | {"source":20,"target":17,"value":3},
109 | {"source":20,"target":18,"value":3},
110 | {"source":20,"target":19,"value":4},
111 | {"source":21,"target":16,"value":3},
112 | {"source":21,"target":17,"value":3},
113 | {"source":21,"target":18,"value":3},
114 | {"source":21,"target":19,"value":3},
115 | {"source":21,"target":20,"value":5},
116 | {"source":22,"target":16,"value":3},
117 | {"source":22,"target":17,"value":3},
118 | {"source":22,"target":18,"value":3},
119 | {"source":22,"target":19,"value":3},
120 | {"source":22,"target":20,"value":4},
121 | {"source":22,"target":21,"value":4},
122 | {"source":23,"target":16,"value":3},
123 | {"source":23,"target":17,"value":3},
124 | {"source":23,"target":18,"value":3},
125 | {"source":23,"target":19,"value":3},
126 | {"source":23,"target":20,"value":4},
127 | {"source":23,"target":21,"value":4},
128 | {"source":23,"target":22,"value":4},
129 | {"source":23,"target":12,"value":2},
130 | {"source":23,"target":11,"value":9},
131 | {"source":24,"target":23,"value":2},
132 | {"source":24,"target":11,"value":7},
133 | {"source":25,"target":24,"value":13},
134 | {"source":25,"target":23,"value":1},
135 | {"source":25,"target":11,"value":12},
136 | {"source":26,"target":24,"value":4},
137 | {"source":26,"target":11,"value":31},
138 | {"source":26,"target":16,"value":1},
139 | {"source":26,"target":25,"value":1},
140 | {"source":27,"target":11,"value":17},
141 | {"source":27,"target":23,"value":5},
142 | {"source":27,"target":25,"value":5},
143 | {"source":27,"target":24,"value":1},
144 | {"source":27,"target":26,"value":1},
145 | {"source":28,"target":11,"value":8},
146 | {"source":28,"target":27,"value":1},
147 | {"source":29,"target":23,"value":1},
148 | {"source":29,"target":27,"value":1},
149 | {"source":29,"target":11,"value":2},
150 | {"source":30,"target":23,"value":1},
151 | {"source":31,"target":30,"value":2},
152 | {"source":31,"target":11,"value":3},
153 | {"source":31,"target":23,"value":2},
154 | {"source":31,"target":27,"value":1},
155 | {"source":32,"target":11,"value":1},
156 | {"source":33,"target":11,"value":2},
157 | {"source":33,"target":27,"value":1},
158 | {"source":34,"target":11,"value":3},
159 | {"source":34,"target":29,"value":2},
160 | {"source":35,"target":11,"value":3},
161 | {"source":35,"target":34,"value":3},
162 | {"source":35,"target":29,"value":2},
163 | {"source":36,"target":34,"value":2},
164 | {"source":36,"target":35,"value":2},
165 | {"source":36,"target":11,"value":2},
166 | {"source":36,"target":29,"value":1},
167 | {"source":37,"target":34,"value":2},
168 | {"source":37,"target":35,"value":2},
169 | {"source":37,"target":36,"value":2},
170 | {"source":37,"target":11,"value":2},
171 | {"source":37,"target":29,"value":1},
172 | {"source":38,"target":34,"value":2},
173 | {"source":38,"target":35,"value":2},
174 | {"source":38,"target":36,"value":2},
175 | {"source":38,"target":37,"value":2},
176 | {"source":38,"target":11,"value":2},
177 | {"source":38,"target":29,"value":1},
178 | {"source":39,"target":25,"value":1},
179 | {"source":40,"target":25,"value":1},
180 | {"source":41,"target":24,"value":2},
181 | {"source":41,"target":25,"value":3},
182 | {"source":42,"target":41,"value":2},
183 | {"source":42,"target":25,"value":2},
184 | {"source":42,"target":24,"value":1},
185 | {"source":43,"target":11,"value":3},
186 | {"source":43,"target":26,"value":1},
187 | {"source":43,"target":27,"value":1},
188 | {"source":44,"target":28,"value":3},
189 | {"source":44,"target":11,"value":1},
190 | {"source":45,"target":28,"value":2},
191 | {"source":47,"target":46,"value":1},
192 | {"source":48,"target":47,"value":2},
193 | {"source":48,"target":25,"value":1},
194 | {"source":48,"target":27,"value":1},
195 | {"source":48,"target":11,"value":1},
196 | {"source":49,"target":26,"value":3},
197 | {"source":49,"target":11,"value":2},
198 | {"source":50,"target":49,"value":1},
199 | {"source":50,"target":24,"value":1},
200 | {"source":51,"target":49,"value":9},
201 | {"source":51,"target":26,"value":2},
202 | {"source":51,"target":11,"value":2},
203 | {"source":52,"target":51,"value":1},
204 | {"source":52,"target":39,"value":1},
205 | {"source":53,"target":51,"value":1},
206 | {"source":54,"target":51,"value":2},
207 | {"source":54,"target":49,"value":1},
208 | {"source":54,"target":26,"value":1},
209 | {"source":55,"target":51,"value":6},
210 | {"source":55,"target":49,"value":12},
211 | {"source":55,"target":39,"value":1},
212 | {"source":55,"target":54,"value":1},
213 | {"source":55,"target":26,"value":21},
214 | {"source":55,"target":11,"value":19},
215 | {"source":55,"target":16,"value":1},
216 | {"source":55,"target":25,"value":2},
217 | {"source":55,"target":41,"value":5},
218 | {"source":55,"target":48,"value":4},
219 | {"source":56,"target":49,"value":1},
220 | {"source":56,"target":55,"value":1},
221 | {"source":57,"target":55,"value":1},
222 | {"source":57,"target":41,"value":1},
223 | {"source":57,"target":48,"value":1},
224 | {"source":58,"target":55,"value":7},
225 | {"source":58,"target":48,"value":7},
226 | {"source":58,"target":27,"value":6},
227 | {"source":58,"target":57,"value":1},
228 | {"source":58,"target":11,"value":4},
229 | {"source":59,"target":58,"value":15},
230 | {"source":59,"target":55,"value":5},
231 | {"source":59,"target":48,"value":6},
232 | {"source":59,"target":57,"value":2},
233 | {"source":60,"target":48,"value":1},
234 | {"source":60,"target":58,"value":4},
235 | {"source":60,"target":59,"value":2},
236 | {"source":61,"target":48,"value":2},
237 | {"source":61,"target":58,"value":6},
238 | {"source":61,"target":60,"value":2},
239 | {"source":61,"target":59,"value":5},
240 | {"source":61,"target":57,"value":1},
241 | {"source":61,"target":55,"value":1},
242 | {"source":62,"target":55,"value":9},
243 | {"source":62,"target":58,"value":17},
244 | {"source":62,"target":59,"value":13},
245 | {"source":62,"target":48,"value":7},
246 | {"source":62,"target":57,"value":2},
247 | {"source":62,"target":41,"value":1},
248 | {"source":62,"target":61,"value":6},
249 | {"source":62,"target":60,"value":3},
250 | {"source":63,"target":59,"value":5},
251 | {"source":63,"target":48,"value":5},
252 | {"source":63,"target":62,"value":6},
253 | {"source":63,"target":57,"value":2},
254 | {"source":63,"target":58,"value":4},
255 | {"source":63,"target":61,"value":3},
256 | {"source":63,"target":60,"value":2},
257 | {"source":63,"target":55,"value":1},
258 | {"source":64,"target":55,"value":5},
259 | {"source":64,"target":62,"value":12},
260 | {"source":64,"target":48,"value":5},
261 | {"source":64,"target":63,"value":4},
262 | {"source":64,"target":58,"value":10},
263 | {"source":64,"target":61,"value":6},
264 | {"source":64,"target":60,"value":2},
265 | {"source":64,"target":59,"value":9},
266 | {"source":64,"target":57,"value":1},
267 | {"source":64,"target":11,"value":1},
268 | {"source":65,"target":63,"value":5},
269 | {"source":65,"target":64,"value":7},
270 | {"source":65,"target":48,"value":3},
271 | {"source":65,"target":62,"value":5},
272 | {"source":65,"target":58,"value":5},
273 | {"source":65,"target":61,"value":5},
274 | {"source":65,"target":60,"value":2},
275 | {"source":65,"target":59,"value":5},
276 | {"source":65,"target":57,"value":1},
277 | {"source":65,"target":55,"value":2},
278 | {"source":66,"target":64,"value":3},
279 | {"source":66,"target":58,"value":3},
280 | {"source":66,"target":59,"value":1},
281 | {"source":66,"target":62,"value":2},
282 | {"source":66,"target":65,"value":2},
283 | {"source":66,"target":48,"value":1},
284 | {"source":66,"target":63,"value":1},
285 | {"source":66,"target":61,"value":1},
286 | {"source":66,"target":60,"value":1},
287 | {"source":67,"target":57,"value":3},
288 | {"source":68,"target":25,"value":5},
289 | {"source":68,"target":11,"value":1},
290 | {"source":68,"target":24,"value":1},
291 | {"source":68,"target":27,"value":1},
292 | {"source":68,"target":48,"value":1},
293 | {"source":68,"target":41,"value":1},
294 | {"source":69,"target":25,"value":6},
295 | {"source":69,"target":68,"value":6},
296 | {"source":69,"target":11,"value":1},
297 | {"source":69,"target":24,"value":1},
298 | {"source":69,"target":27,"value":2},
299 | {"source":69,"target":48,"value":1},
300 | {"source":69,"target":41,"value":1},
301 | {"source":70,"target":25,"value":4},
302 | {"source":70,"target":69,"value":4},
303 | {"source":70,"target":68,"value":4},
304 | {"source":70,"target":11,"value":1},
305 | {"source":70,"target":24,"value":1},
306 | {"source":70,"target":27,"value":1},
307 | {"source":70,"target":41,"value":1},
308 | {"source":70,"target":58,"value":1},
309 | {"source":71,"target":27,"value":1},
310 | {"source":71,"target":69,"value":2},
311 | {"source":71,"target":68,"value":2},
312 | {"source":71,"target":70,"value":2},
313 | {"source":71,"target":11,"value":1},
314 | {"source":71,"target":48,"value":1},
315 | {"source":71,"target":41,"value":1},
316 | {"source":71,"target":25,"value":1},
317 | {"source":72,"target":26,"value":2},
318 | {"source":72,"target":27,"value":1},
319 | {"source":72,"target":11,"value":1},
320 | {"source":73,"target":48,"value":2},
321 | {"source":74,"target":48,"value":2},
322 | {"source":74,"target":73,"value":3},
323 | {"source":75,"target":69,"value":3},
324 | {"source":75,"target":68,"value":3},
325 | {"source":75,"target":25,"value":3},
326 | {"source":75,"target":48,"value":1},
327 | {"source":75,"target":41,"value":1},
328 | {"source":75,"target":70,"value":1},
329 | {"source":75,"target":71,"value":1},
330 | {"source":76,"target":64,"value":1},
331 | {"source":76,"target":65,"value":1},
332 | {"source":76,"target":66,"value":1},
333 | {"source":76,"target":63,"value":1},
334 | {"source":76,"target":62,"value":1},
335 | {"source":76,"target":48,"value":1},
336 | {"source":76,"target":58,"value":1}
337 | ]
338 | }
339 |
--------------------------------------------------------------------------------
/d3heatmap/d3js/d3.scale.chromatic.v1.min.js:
--------------------------------------------------------------------------------
1 | // https://d3js.org/d3-scale-chromatic/ v1.5.0 Copyright 2019 Mike Bostock
2 | !function(f,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("d3-interpolate"),require("d3-color")):"function"==typeof define&&define.amd?define(["exports","d3-interpolate","d3-color"],e):e((f=f||self).d3=f.d3||{},f.d3,f.d3)}(this,function(f,e,d){"use strict";function a(f){for(var e=f.length/6|0,d=new Array(e),a=0;a1)&&(f-=Math.floor(f));var e=Math.abs(f-.5);return wf.h=360*f-100,wf.s=1.5-1.5*e,wf.l=.8-.9*e,wf+""},f.interpolateRdBu=x,f.interpolateRdGy=g,f.interpolateRdPu=N,f.interpolateRdYlBu=v,f.interpolateRdYlGn=C,f.interpolateReds=hf,f.interpolateSinebow=function(f){var e;return f=(.5-f)*Math.PI,Af.r=255*(e=Math.sin(f))*e,Af.g=255*(e=Math.sin(f+Pf))*e,Af.b=255*(e=Math.sin(f+Bf))*e,Af+""},f.interpolateSpectral=I,f.interpolateTurbo=function(f){return f=Math.max(0,Math.min(1,f)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+f*(1172.33-f*(10793.56-f*(33300.12-f*(38394.49-14825.05*f)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+f*(557.33+f*(1225.33-f*(3574.96-f*(1073.77+707.56*f)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+f*(3211.1-f*(15327.97-f*(27814-f*(22569.18-6838.66*f)))))))+")"},f.interpolateViridis=xf,f.interpolateWarm=yf,f.interpolateYlGn=Z,f.interpolateYlGnBu=U,f.interpolateYlOrBr=ff,f.interpolateYlOrRd=df,f.schemeAccent=b,f.schemeBlues=af,f.schemeBrBG=u,f.schemeBuGn=L,f.schemeBuPu=q,f.schemeCategory10=c,f.schemeDark2=t,f.schemeGnBu=T,f.schemeGreens=bf,f.schemeGreys=nf,f.schemeOrRd=k,f.schemeOranges=pf,f.schemePRGn=y,f.schemePaired=n,f.schemePastel1=r,f.schemePastel2=o,f.schemePiYG=w,f.schemePuBu=E,f.schemePuBuGn=W,f.schemePuOr=P,f.schemePuRd=H,f.schemePurples=of,f.schemeRdBu=G,f.schemeRdGy=R,f.schemeRdPu=K,f.schemeRdYlBu=Y,f.schemeRdYlGn=O,f.schemeReds=mf,f.schemeSet1=i,f.schemeSet2=l,f.schemeSet3=m,f.schemeSpectral=S,f.schemeTableau10=h,f.schemeYlGn=X,f.schemeYlGnBu=Q,f.schemeYlOrBr=$,f.schemeYlOrRd=ef,Object.defineProperty(f,"__esModule",{value:!0})});
--------------------------------------------------------------------------------
/d3heatmap/d3heatmap.py:
--------------------------------------------------------------------------------
1 | """Heatmap in d3 javascript."""
2 | # --------------------------------------------------
3 | # Name : d3heatmap.py
4 | # Author : E.Taskesen
5 | # Contact : erdogant@gmail.com
6 | # github : https://github.com/erdogant/d3heatmap
7 | # Licence : See licences
8 | # --------------------------------------------------
9 |
10 | from clusteval import clusteval
11 | import numpy as np
12 | import pandas as pd
13 | import webbrowser
14 | import tempfile
15 | from shutil import copyfile
16 | import os
17 | import time
18 | from ismember import ismember
19 |
20 | curpath = os.path.dirname(os.path.abspath(__file__))
21 |
22 |
23 | # %%
24 | def heatmap(df, color='cluster', path=None, title='d3heatmap', description=None, vmax=None, width=720, height=720, showfig=True, stroke='red', verbose=3):
25 | """Heatmap in d3js.
26 |
27 | Parameters
28 | ----------
29 | df : pd.DataFrame()
30 | Input data. The index and column names are used for the row/column naming.
31 | color : Numpy array
32 | Should be in the same order as the columns and of the input dataframe
33 | None or 'cluster': a clustering approach is used for coloring.
34 | path : String, (Default: user temp directory)
35 | Directory path to save the output, such as 'c://temp/index.html'
36 | title : String, (default: 'd3 Heatmap!')
37 | Title text.
38 | description : String, (default: 'Heatmap description')
39 | Description text of the heatmap.
40 | vmax : Bool, (default: 100).
41 | Range of colors starting with maximum value. Increasing this value will color the cells more discrete.
42 | * 1 : cells above value >1 are capped.
43 | * None : cells are colored based on the maximum value in the input data.
44 | width : int, (default: 500).
45 | Width of the window.
46 | height : int, (default: 500).
47 | height of the window.
48 | stroke : String, (default: 'red').
49 | Color of the recangle when hovering over a cell.
50 | * 'red'
51 | * 'black'
52 | showfig : Bool, (default: True)
53 | Open browser with heatmap.
54 | verbose : int [0-5], (default: 3)
55 | Verbosity to print the working-status. The higher the number, the more information.
56 | * 0: None
57 | * 1: Error
58 | * 2: Warning
59 | * 3: Info
60 | * 4: Debug
61 | * 5: Trace
62 |
63 | Example
64 | -------
65 | >>> # Load library
66 | >>> from d3heatmap import d3heatmap as d3
67 | >>> # Import example
68 | >>> df = d3.import_example()
69 | >>> # Create heatmap
70 | >>> results = d3.heatmap(df, vmax=1)
71 |
72 | Returns
73 | -------
74 | out : dict.
75 | output path names.
76 |
77 | """
78 | if len(df.columns.unique())!=len(df.columns):
79 | if verbose>=2: print('[d3heatmap] >Warning: Input data should contain unique column names otherwise d3js randomly removes the non-unique ones.')
80 | if len(df.index.unique())!=len(df.index):
81 | if verbose>=2: print('[d3heatmap] >Warning: Input data should contain unique index names otherwise d3js randomly removes the non-unique ones.')
82 | if description is None:
83 | description = "This heatmap is created in d3js using https://github.com/erdogant/d3heatmap.\n\nA network can be represented by an adjacency matrix, where each cell ij represents an edge from vertex i to vertex j.\n\nGiven this two-dimensional representation of a graph, a natural visualization is to show the matrix! However, the effectiveness of a matrix diagram is heavily dependent on the order of rows and columns: if related nodes are placed closed to each other, it is easier to identify clusters and bridges.\nWhile path-following is harder in a matrix view than in a node-link diagram, matrices have other advantages. As networks get large and highly connected, node-link diagrams often devolve into giant hairballs of line crossings. Line crossings are impossible with matrix views. Matrix cells can also be encoded to show additional data; here color depicts clusters computed by a community-detection algorithm."
84 | if isinstance(color, str) and color=='cluster':
85 | color=None
86 |
87 | # Rescale data
88 | if vmax is not None:
89 | df = _scale(df, vmax=vmax, make_round=False, verbose=verbose)
90 | # if vmin is None:
91 | # vmin = np.min(df.values)
92 | if vmax is None:
93 | vmax = np.max(df.values)
94 | if verbose>=3: print('[d3heatmap] >Set vmax: %.0g.' %(vmax))
95 |
96 | # Get path to files
97 | d3_library = os.path.abspath(os.path.join(curpath, 'd3js/d3.v2.min.js'))
98 | d3_script = os.path.abspath(os.path.join(curpath, 'd3js/d3heatmap.html'))
99 |
100 | # Check path
101 | filename, dirpath, path = _path_check(path, verbose)
102 |
103 | # Copy files to destination directory
104 | # copyfile(d3_library, os.path.join(dirpath, os.path.basename(d3_library)))
105 | copyfile(d3_script, path)
106 |
107 | # Collect node names
108 | nodes = df.columns.astype(str).values
109 |
110 | # Convert into adj into vector
111 | dfvec = adjmat2vec(df)
112 | uinode, idx = np.unique(nodes, return_index=True)
113 | for node, i in zip(uinode, idx):
114 | dfvec['source'] = dfvec['source'].replace(node, i)
115 | dfvec['target'] = dfvec['target'].replace(node, i)
116 |
117 | # Write to disk (file is not used)
118 | basename, ext = os.path.splitext(filename)
119 | PATHNAME_TO_CSV = os.path.join(dirpath, basename + '.csv')
120 | # dfvec.to_csv(PATHNAME_TO_CSV, index=False)
121 |
122 | # Cluster the nodes
123 | if color is None:
124 | ce = clusteval()
125 | results = ce.fit(df.values)
126 | color = results['labx']
127 |
128 | # Embed the Data in the HTML. Note that the embedding is an important stap te prevent security issues by the browsers.
129 | # Most (if not all) browser do not accept to read a file using d3.csv or so. It then requires security-by-passes, but thats not the way to go.
130 | # An alternative is use local-host and CORS but then the approach is not user-friendly coz setting up this, is not so straightforward.
131 | # It leaves us by embedding the data in the HTML. Thats what we are going to do here.
132 |
133 | NODE_STR = '\n{\n"nodes":\n[\n'
134 | for i in range(0, len(nodes)):
135 | NODE_STR = NODE_STR + '{"name":' + '"' + nodes[i] + '"' + ',' + '"cluster":' + str(color[i]) + "},"
136 | NODE_STR = NODE_STR + '\n'
137 | NODE_STR = NODE_STR + '],\n'
138 |
139 | EDGE_STR = '"links":\n[\n'
140 | for i in range(0, dfvec.shape[0]):
141 | EDGE_STR = EDGE_STR + '{"source":' + str(dfvec.iloc[i, 0]) + ',' + '"target":' + str(dfvec.iloc[i, 1]) + ',' + '"value":' + str(dfvec.iloc[i, 2]) + '},'
142 | EDGE_STR = EDGE_STR + '\n'
143 | EDGE_STR = EDGE_STR + ']\n}'
144 |
145 | # Final data string
146 | DATA_STR = NODE_STR + EDGE_STR
147 |
148 | # Read the data
149 | # {
150 | # "nodes":
151 | # [
152 | # {"name":"Name A","cluster":1},
153 | # {"name":"Name B","cluster":2},
154 | # {"name":"Name C","cluster":2},
155 | # {"name":"Name D","cluster":3},
156 | # ],
157 | # "links":
158 | # [
159 | # {"source":0,"target":1,"value":1},
160 | # {"source":2,"target":2,"value":1},
161 | # {"source":3,"target":1,"value":1},
162 | # ]
163 | # }
164 |
165 | # Import in the file
166 | with open(path, 'r', encoding="utf8", errors='ignore') as file: d3graphscript = file.read()
167 |
168 | # Read the d3 html with script file
169 | d3graphscript = d3graphscript.replace('$DESCRIPTION$', str(description))
170 | d3graphscript = d3graphscript.replace('$TITLE$', str(title))
171 | d3graphscript = d3graphscript.replace('$WIDTH$', str(width))
172 | d3graphscript = d3graphscript.replace('$WIDTH_DROPDOWN$', str(int(width + 200)))
173 | d3graphscript = d3graphscript.replace('$HEIGHT$', str(height))
174 | d3graphscript = d3graphscript.replace('$STROKE$', str(stroke))
175 | d3graphscript = d3graphscript.replace('$DATA_PATH$', filename)
176 | d3graphscript = d3graphscript.replace('$DATA_COMES_HERE$', DATA_STR)
177 |
178 | # Write to file
179 | with open(path, 'w', encoding="utf8", errors='ignore') as file: file.write(d3graphscript)
180 | # Open browser with heatmap
181 | if showfig: webbrowser.open(path, new=1)
182 |
183 | # Return
184 | out = {}
185 | out['filename'] = filename
186 | out['dirpath'] = dirpath
187 | out['path'] = path
188 | out['csv'] = PATHNAME_TO_CSV
189 | return out
190 |
191 |
192 | # %%
193 | def matrix(df, path=None, title='d3heatmap', description='Heatmap description', width=500, height=500, fontsize=10, cmap='interpolateInferno', scale=False, vmin=None, vmax=None, showfig=True, stroke='red', overwrite=True, verbose=3):
194 | """Heatmap in d3 javascript.
195 |
196 | Parameters
197 | ----------
198 | df : pd.DataFrame()
199 | Input data. The index and column names are used for the row/column naming.
200 | path : String, (Default: user temp directory)
201 | Directory path to save the output, such as 'c://temp/index.html'
202 | title : String, (default: 'd3 Heatmap!')
203 | Title text.
204 | description : String, (default: 'Heatmap description')
205 | Description text of the heatmap.
206 | width : int, (default: 500).
207 | Width of the window.
208 | height : int, (default: 500).
209 | height of the window.
210 | fontsize : int, (default: 10).
211 | Font size for the X and Y labels.
212 | scale : Bool, (default: True).
213 | Scale the values between [0-100].
214 | vmin : Bool, (default: 0).
215 | Range of colors starting with minimum value.
216 | * 1 : cells with value <1 are coloured white.
217 | * None : cells are colored based on the minimum value in the input data.
218 | vmax : Bool, (default: 100).
219 | Range of colors starting with maximum value.
220 | * 100 : cells above value >100 are capped.
221 | * None : cells are colored based on the maximum value in the input data.
222 | stroke : String, (default: 'red').
223 | Color of the recangle when hovering over a cell.
224 | * 'red'
225 | * 'black'
226 | showfig : Bool, (default: True)
227 | Open browser with heatmap.
228 | overwrite : Bool, (default: False)
229 | Overwrite existing file on the path location.
230 | cmap : String, (default: 'interpolateInferno').
231 | The colormap scheme. This can be found at: https://github.com/d3/d3-scale-chromatic.
232 | Categorical:
233 | * 'schemeCategory10'
234 | * 'schemeAccent'
235 | Diverging:
236 | * 'interpolateInferno'
237 | * 'interpolatePRGn'
238 | Single color:
239 | * 'interpolateBlues'
240 | * 'interpolateGreens'
241 | Sequential:
242 | * 'interpolateTurbo'
243 | * 'interpolateViridis'
244 | * 'interpolateInferno'
245 | Cyclic:
246 | * 'interpolateRainbow'
247 | * 'interpolateSinebow'
248 | verbose : int [0-5], (default: 3)
249 | Verbosity to print the working-status. The higher the number, the more information.
250 | * 0: None, 1: Error, 2: Warning, 3: Info, 4: Debug, 5: Trace
251 |
252 | Example
253 | -------
254 | >>> # Load library
255 | >>> from d3heatmap import d3heatmap as d3
256 | >>> # Import example
257 | >>> df = d3.import_example(size=(6,20))
258 | >>> # Create heatmap
259 | >>> paths = d3.matrix(df)
260 | >>> # The dataframe contains more columns then rows. Adjust the size and color differently.
261 | >>> paths = d3.matrix(df, fontsize=10, title='Hooray!', description='d3 matrix is created using https://github.com/erdogant/d3heatmap.', path='c:/temp/example/d3_matrix.html', width=600, height=300, cmap='interpolateGreens', vmin=1)
262 |
263 | Returns
264 | -------
265 | out : dict.
266 | output path names.
267 |
268 | """
269 | if cmap in ['schemeCategory10', 'schemeAccent', 'schemeDark2', 'schemePaired', 'schemePastel2', 'schemePastel1', 'schemeSet1', 'schemeSet2', 'schemeSet3', 'schemeTableau10']:
270 | cmap_type='scaleOrdinal'
271 | if verbose>=3: print('[d3heatmap] >d3 cmap type is set to %s' %(cmap_type))
272 | else:
273 | cmap_type='scaleSequential'
274 |
275 | if len(df.columns.unique())!=len(df.columns):
276 | if verbose>=2: print('[d3heatmap] >Warning: Input data should contain unique column names otherwise d3js randomly removes the non-unique ones.')
277 | if len(df.index.unique())!=len(df.index):
278 | if verbose>=2: print('[d3heatmap] >Warning: Input data should contain unique index names otherwise d3js randomly removes the non-unique ones.')
279 |
280 | # Rescale data between 0-100
281 | if scale:
282 | df = _scale(df, verbose=verbose)
283 | if (not scale) and (vmin is not None) and (vmax is not None):
284 | if verbose>=3: print('[d3heatmap] >Data is not scaled. Tip: set vmin=None and vmax=None to range colors between min-max of your data.')
285 | if vmin is None:
286 | vmin = np.min(df.values)
287 | if vmax is None:
288 | vmax = np.max(df.values)
289 | if verbose>=3: print('[d3heatmap] >vmin is set to: %g' %(vmin))
290 | if verbose>=3: print('[d3heatmap] >vmax is set to: %g' %(vmax))
291 |
292 | # Get path to files
293 | d3_library = os.path.abspath(os.path.join(curpath, 'd3js/d3.v4.js'))
294 | d3_chromatic = os.path.abspath(os.path.join(curpath, 'd3js/d3.scale.chromatic.v1.min.js'))
295 | d3_script = os.path.abspath(os.path.join(curpath, 'd3js/d3script.html'))
296 |
297 | # Set fontsize for x-axis, y-axis
298 | fontsize_x = fontsize
299 | fontsize_y = fontsize
300 |
301 | # Check path
302 | filename, dirpath, path = _path_check(path, verbose)
303 |
304 | # Copy files to destination directory
305 | copyfile(d3_library, os.path.join(dirpath, os.path.basename(d3_library)))
306 | copyfile(d3_chromatic, os.path.join(dirpath, os.path.basename(d3_chromatic)))
307 | copyfile(d3_script, path)
308 |
309 | # Convert into adj into vector
310 | dfvec = adjmat2vec(df)
311 | dfvec = dfvec.rename(columns={'source': 'variable', 'target': 'group', 'weight': 'value'})
312 |
313 | # Write to disk (file is not used)
314 | basename, ext = os.path.splitext(filename)
315 | PATHNAME_TO_CSV = os.path.join(dirpath, basename + '.csv')
316 | # dfvec.to_csv(PATHNAME_TO_CSV, index=False)
317 |
318 | # Embed the Data in the HTML. Note that the embedding is an important stap te prevent security issues by the browsers.
319 | # Most (if not all) browser do not accept to read a file using d3.csv or so. It then requires security-by-passes, but thats not the way to go.
320 | # An alternative is use local-host and CORS but then the approach is not user-friendly coz setting up this, is not so straightforward.
321 | # It leaves us by embedding the data in the HTML. Thats what we are going to do here.
322 | DATA_STR = ''
323 | for i in range(0, dfvec.shape[0]):
324 | newline = '{group : "' + str(dfvec['group'].iloc[i]) + '", variable : "' + str(dfvec['variable'].iloc[i]) + '", value : "' + str(dfvec['value'].iloc[i]) +'"},'
325 | newline = newline + '\n'
326 | DATA_STR = DATA_STR + newline
327 |
328 | # Read the data
329 | # var data =
330 | # [
331 | # {"group":"A", "variable":"v1", "value":"3"},
332 | # {"group":"A", "variable":"v2", "value":"5"},
333 | # {"group":"B", "variable":"v1", "value":"10"},
334 | # {"group":"B", "variable":"v2", "value":"10"}
335 | # ]
336 |
337 | # Import in the file
338 | with open(path, 'r') as file: d3graphscript = file.read()
339 |
340 | # Read the d3 html with script file
341 | d3graphscript = d3graphscript.replace('$DESCRIPTION$', str(description))
342 | d3graphscript = d3graphscript.replace('$TITLE$', str(title))
343 |
344 | d3graphscript = d3graphscript.replace('$WIDTH$', str(width))
345 | d3graphscript = d3graphscript.replace('$HEIGHT$', str(height))
346 |
347 | d3graphscript = d3graphscript.replace('$VMIN$', str(vmin))
348 | d3graphscript = d3graphscript.replace('$VMAX$', str(vmax))
349 |
350 | d3graphscript = d3graphscript.replace('$FONTSIZE_X$', str(fontsize_x))
351 | d3graphscript = d3graphscript.replace('$FONTSIZE_Y$', str(fontsize_y))
352 |
353 | d3graphscript = d3graphscript.replace('$STROKE$', str(stroke))
354 | d3graphscript = d3graphscript.replace('$CMAP$', str(cmap))
355 | d3graphscript = d3graphscript.replace('$CMAP_TYPE$', str(cmap_type))
356 |
357 | d3graphscript = d3graphscript.replace('$DATA_PATH$', filename)
358 | d3graphscript = d3graphscript.replace('$DATA_COMES_HERE$', DATA_STR)
359 |
360 | # Delete file if exists
361 | if overwrite:
362 | os.remove(path)
363 | if os.path.isfile(path):
364 | if verbose>=2: print('[d3heatmap] >Warning: File already exists! Delete it manually or set the parameter "overwrite=True"')
365 | else:
366 | # Write to file
367 | if verbose>=3: print('[d3heatmap] >Writing to disk..')
368 | with open(path, 'w', encoding="utf8", errors='ignore') as file: file.write(d3graphscript)
369 | # Sleep a bit to make sure file is written
370 | time.sleep(0.5)
371 | # Open browser with heatmap
372 | if showfig: webbrowser.open(path, new=1)
373 |
374 | # Return
375 | out = {}
376 | out['filename'] = filename
377 | out['dirpath'] = dirpath
378 | out['path'] = path
379 | out['csv'] = PATHNAME_TO_CSV
380 | return out
381 |
382 |
383 | # %% Import example dataset from github.
384 | def import_example(size=(50, 50), verbose=3):
385 | """Generate example dataset.
386 |
387 | Description
388 | -----------
389 | Generate random adjacency matrix.
390 |
391 | Parameters
392 | ----------
393 | verbose : int, optional
394 | Print progress to screen. The default is 3.
395 | 0: None, 1: ERROR, 2: WARN, 3: INFO (default), 4: DEBUG, 5: TRACE
396 |
397 | Returns
398 | -------
399 | pd.DataFrame()
400 | Dataset containing mixed features.
401 |
402 | """
403 | df = pd.DataFrame(np.random.randint(0, 10, size=size))
404 |
405 | # Return
406 | return df
407 |
408 |
409 | # %%
410 | def _path_check(path, verbose):
411 | # Check wether path
412 | if path is None:
413 | path = os.path.join(tempfile.gettempdir(), 'index.html')
414 | # Check wether dir + path
415 | dirpath, filename = os.path.split(path)
416 | # if input is single file, attach the absolute path.
417 | if dirpath=='':
418 | path = os.path.join(tempfile.gettempdir(), filename)
419 | dirpath, filename = os.path.split(path)
420 | # Check before proceeding
421 | if not ('.html' in filename):
422 | raise ValueError('[d3heatmap] >path should contain the file extension: ".html" ')
423 | # Create dir
424 | if not os.path.isdir(dirpath):
425 | if verbose>=2: print('[d3heatmap] >Warning: Creating directory [%s]' %(dirpath))
426 | os.makedirs(dirpath, exist_ok=True)
427 | # Final
428 | path = os.path.abspath(path)
429 | dirpath, filename = os.path.split(path)
430 | return filename, dirpath, path
431 |
432 |
433 | # %% Scaling
434 | def _scale(X, vmax=100, make_round=True, verbose=3):
435 | """Scale data.
436 |
437 | Description
438 | -----------
439 | Scaling in range by X*(100/max(X))
440 |
441 | Parameters
442 | ----------
443 | X : array-like
444 | Input image data.
445 | verbose : int (default : 3)
446 | Print to screen. 0: None, 1: Error, 2: Warning, 3: Info, 4: Debug, 5: Trace.
447 |
448 | Returns
449 | -------
450 | df : array-like
451 | Scaled image.
452 |
453 | """
454 | if verbose>=3: print('[d3heatmap] >Scaling image between [min-100]')
455 | try:
456 | # Normalizing between 0-100
457 | # X = X - X.min()
458 | X = X / X.max().max()
459 | X = X * vmax
460 | if make_round:
461 | X = np.round(X)
462 | except:
463 | if verbose>=2: print('[d3heatmap] >Warning: Scaling not possible.')
464 |
465 | return X
466 |
467 |
468 | # %% Convert adjacency matrix to vector
469 | def vec2adjmat(source, target, weight=None, symmetric=True):
470 | """Convert source and target into adjacency matrix.
471 |
472 | Parameters
473 | ----------
474 | source : list
475 | The source node.
476 | target : list
477 | The target node.
478 | weight : list of int
479 | The Weights between the source-target values
480 | symmetric : bool, optional
481 | Make the adjacency matrix symmetric with the same number of rows as columns. The default is True.
482 |
483 | Returns
484 | -------
485 | pd.DataFrame
486 | adjacency matrix.
487 |
488 | Examples
489 | --------
490 | >>> source=['Cloudy','Cloudy','Sprinkler','Rain']
491 | >>> target=['Sprinkler','Rain','Wet_Grass','Wet_Grass']
492 | >>> vec2adjmat(source, target)
493 | >>>
494 | >>> weight=[1,2,1,3]
495 | >>> vec2adjmat(source, target, weight=weight)
496 |
497 | """
498 | if len(source)!=len(target): raise Exception('[hnet] >Source and Target should have equal elements.')
499 | if weight is None: weight = [1]*len(source)
500 |
501 | df = pd.DataFrame(np.c_[source, target], columns=['source','target'])
502 | # Make adjacency matrix
503 | adjmat = pd.crosstab(df['source'], df['target'], values=weight, aggfunc='sum').fillna(0)
504 | # Get all unique nodes
505 | nodes = np.unique(list(adjmat.columns.values)+list(adjmat.index.values))
506 | # nodes = np.unique(np.c_[adjmat.columns.values, adjmat.index.values].flatten())
507 |
508 | # Make the adjacency matrix symmetric
509 | if symmetric:
510 | # Add missing columns
511 | node_columns = np.setdiff1d(nodes, adjmat.columns.values)
512 | for node in node_columns:
513 | adjmat[node]=0
514 |
515 | # Add missing rows
516 | node_rows = np.setdiff1d(nodes, adjmat.index.values)
517 | adjmat=adjmat.T
518 | for node in node_rows:
519 | adjmat[node]=0
520 | adjmat=adjmat.T
521 |
522 | # Sort to make ordering of columns and rows similar
523 | [IA, IB] = ismember(adjmat.columns.values, adjmat.index.values)
524 | adjmat = adjmat.iloc[IB, :]
525 | adjmat.index.name='source'
526 | adjmat.columns.name='target'
527 |
528 | return(adjmat)
529 |
530 |
531 | # %% Convert adjacency matrix to vector
532 | def adjmat2vec(adjmat, min_weight=0, verbose=3):
533 | """Convert adjacency matrix into vector with source and target.
534 |
535 | Parameters
536 | ----------
537 | adjmat : pd.DataFrame()
538 | Adjacency matrix.
539 |
540 | min_weight : float
541 | edges are returned with a minimum weight.
542 |
543 | Returns
544 | -------
545 | pd.DataFrame()
546 | nodes that are connected based on source and target
547 |
548 | Examples
549 | --------
550 | >>> source=['Cloudy','Cloudy','Sprinkler','Rain']
551 | >>> target=['Sprinkler','Rain','Wet_Grass','Wet_Grass']
552 | >>> adjmat = vec2adjmat(source, target)
553 | >>> vector = adjmat2vec(adjmat)
554 |
555 | """
556 | # Convert adjacency matrix into vector
557 | adjmat = adjmat.stack().reset_index()
558 | # Set columns
559 | adjmat.columns = ['source', 'target', 'weight']
560 | # Remove self loops and no-connected edges
561 | # Iloc1 = adjmat['source']!=adjmat['target']
562 | Iloc2 = adjmat['weight']>=min_weight
563 | # Iloc = Iloc1 & Iloc2
564 | Iloc = Iloc2
565 | # Take only connected nodes
566 | adjmat = adjmat.loc[Iloc, :]
567 | adjmat.reset_index(drop=True, inplace=True)
568 | return(adjmat)
--------------------------------------------------------------------------------
/d3heatmap/d3js/d3heatmap.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 | "$TITLE$"
14 |
229 |
230 |
231 |
232 |
238 |
239 |
240 | $TITLE$
241 |
242 |
251 |
252 |
418 |
419 | $DESCRIPTION$
420 |
--------------------------------------------------------------------------------