diff --git a/README.rst b/README.rst
index 790594a..c6c76c7 100644
--- a/README.rst
+++ b/README.rst
@@ -14,7 +14,8 @@ resulting visualizations and use the editor tool `on this website
`_.
Downloads:
- https://pypi.python.org/pypi/viscm/
+ * https://pypi.python.org/pypi/viscm/
+ * https://anaconda.org/conda-forge/viscm/
Code and bug tracker:
https://github.com/matplotlib/viscm
@@ -23,10 +24,10 @@ Contact:
Nathaniel J. Smith and Stéfan van der Walt
Dependencies:
- * Python 2.6+, or 3.3+
+ * Python 3.7+
* `colorspacious `_
* Matplotlib
* NumPy
License:
- MIT, see LICENSE.txt for details.
+ MIT, see `LICENSE `__ for details.
diff --git a/doc/contributing.md b/doc/contributing.md
new file mode 100644
index 0000000..fc5825b
--- /dev/null
+++ b/doc/contributing.md
@@ -0,0 +1,23 @@
+# Contributing
+
+Install development dependencies:
+
+```
+conda env create # or `mamba env create`
+```
+
+
+## Development install
+
+```
+pip install -e .
+```
+
+
+## Testing the build
+
+```
+rm -rf dist
+python -m build
+pip install dist/*.whl # or `dist/*.tar.gz`
+```
diff --git a/environment.yml b/environment.yml
new file mode 100644
index 0000000..33c0a90
--- /dev/null
+++ b/environment.yml
@@ -0,0 +1,12 @@
+name: "viscm"
+channels:
+ - "conda-forge"
+ - "nodefaults"
+dependencies:
+ - "python ~=3.11"
+ - "numpy ~=1.24"
+ - "matplotlib ~=3.7"
+ - "colorspacious ~=1.1"
+ - "scipy ~=1.10"
+ - pip:
+ - "build ~=0.10"
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..1b53c90
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,48 @@
+[project]
+name = "viscm"
+dynamic = ["version"]
+description = "A colormap tool"
+readme = "README.rst"
+authors = [
+ {name = "Nathaniel J. Smith", email = "njs@pobox.com"},
+ {name = "Stefan van der Walt", email = "stefanv@berkeley.edu"},
+]
+classifiers = [
+ "Development Status :: 3 - Alpha",
+ "Intended Audience :: Developers",
+ "Intended Audience :: Science/Research",
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python :: 3",
+]
+
+requires-python = "~=3.7"
+dependencies = [
+ "numpy",
+ "matplotlib",
+ "colorspacious",
+ "scipy",
+]
+
+[project.urls]
+repository = "https://github.com/matplotlib/viscm"
+# documentation = "https://viscm.readthedocs.io"
+
+[project.license]
+text = "MIT"
+files = ["LICENSE"]
+
+[project.scripts]
+viscm = "viscm.cli:cli"
+
+
+[build-system]
+requires = ["setuptools", "setuptools_scm"]
+build-backend = "setuptools.build_meta"
+
+[tool.setuptools]
+zip-safe = false
+packages = {find = {}}
+package-data = {viscm = ["examples/*"]}
+
+
+# [tool.black]
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 5c6311d..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[bdist_wheel]
-universal=1
-
-[metadata]
-license_file = LICENSE
diff --git a/setup.py b/setup.py
index 796b780..d5d43d7 100644
--- a/setup.py
+++ b/setup.py
@@ -1,32 +1,3 @@
-from setuptools import setup, find_packages
-import sys
-import os.path
+from setuptools import setup
-import numpy as np
-
-# Must be one line or PyPI will cut it off
-DESC = ("A colormap tool")
-
-LONG_DESC = open("README.rst").read()
-
-setup(
- name="viscm",
- version="0.9",
- description=DESC,
- long_description=LONG_DESC,
- author="Nathaniel J. Smith, Stefan van der Walt",
- author_email="njs@pobox.com, stefanv@berkeley.edu",
- url="https://github.com/bids/viscm",
- license="MIT",
- classifiers =
- [ "Development Status :: 3 - Alpha",
- "Intended Audience :: Developers",
- "Intended Audience :: Science/Research",
- "License :: OSI Approved :: MIT License",
- "Programming Language :: Python :: 2",
- "Programming Language :: Python :: 3",
- ],
- packages=find_packages(),
- install_requires=["numpy", "matplotlib", "colorspacious", "scipy"],
- package_data={'viscm': ['examples/*']},
-)
+setup(use_scm_version=True)
diff --git a/viscm/__init__.py b/viscm/__init__.py
index 2152218..f51aa85 100644
--- a/viscm/__init__.py
+++ b/viscm/__init__.py
@@ -1,4 +1,3 @@
-# This file is part of pycam02ucs
# Copyright (C) 2014 Nathaniel Smith
# See file LICENSE.txt for license information.
diff --git a/viscm/__main__.py b/viscm/__main__.py
index db0cdb5..f4b3e03 100644
--- a/viscm/__main__.py
+++ b/viscm/__main__.py
@@ -3,6 +3,5 @@
# Copyright (C) 2015 Stefan van der Walt
# See file LICENSE.txt for license information.
-import sys
-from .gui import main
-main(sys.argv[1:])
+from .cli import cli
+cli()
diff --git a/viscm/cli.py b/viscm/cli.py
new file mode 100644
index 0000000..246ae46
--- /dev/null
+++ b/viscm/cli.py
@@ -0,0 +1,106 @@
+import sys
+
+import matplotlib.pyplot as plt
+
+from viscm import gui
+
+
+def cli():
+ import argparse
+ argv = sys.argv[1:]
+
+ parser = argparse.ArgumentParser(
+ prog="python -m viscm",
+ description="A colormap tool.",
+ )
+ parser.add_argument("action", metavar="ACTION",
+ help="'edit' or 'view' (or 'show', same as 'view')",
+ choices=["edit", "view", "show"],
+ default="edit",
+ nargs="?")
+ parser.add_argument("colormap", metavar="COLORMAP",
+ default=None,
+ help="A .json file saved from the editor, a .py file containing"
+ " a global named `test_cm`, or the name of a matplotlib"
+ " builtin colormap",
+ nargs="?")
+ parser.add_argument("--uniform-space", metavar="SPACE",
+ default="CAM02-UCS",
+ dest="uniform_space",
+ help="The perceptually uniform space to use. Usually "
+ "you should leave this alone. You can pass 'CIELab' "
+ "if you're curious how uniform some colormap is in "
+ "CIELab space. You can pass 'buggy-CAM02-UCS' if "
+ "you're trying to reproduce the matplotlib colormaps "
+ "(which turn out to have had a small bug in the "
+ "assumed sRGB viewing conditions) from their bezier "
+ "curves.")
+ parser.add_argument("-t", "--type", type=str,
+ default="linear", choices=["linear", "diverging", "diverging-continuous"],
+ help="Choose a colormap type. Supported options are 'linear', 'diverging', and 'diverging-continuous")
+ parser.add_argument("-m", "--method", type=str,
+ default="CatmulClark", choices=["Bezier", "CatmulClark"],
+ help="Choose a spline construction method. 'CatmulClark' is the default, but you may choose the legacy option 'Bezier'")
+ parser.add_argument("--save", metavar="FILE",
+ default=None,
+ help="Immediately save visualization to a file "
+ "(view-mode only).")
+ parser.add_argument("--quit", default=False, action="store_true",
+ help="Quit immediately after starting "
+ "(useful with --save).")
+ args = parser.parse_args(argv)
+
+ cm = gui.Colormap(args.type, args.method, args.uniform_space)
+ app = gui.QtWidgets.QApplication([])
+
+ if args.colormap:
+ cm.load(args.colormap)
+
+
+ # Easter egg! I keep typing 'show' instead of 'view' so accept both
+ if args.action in ("view", "show"):
+ if cm is None:
+ sys.exit("Please specify a colormap")
+ fig = plt.figure()
+ figureCanvas = gui.FigureCanvas(fig)
+ v = gui.viscm(cm.cmap, name=cm.name, figure=fig, uniform_space=cm.uniform_space)
+ mainwindow = gui.ViewerWindow(figureCanvas, v, cm.name)
+ if args.save is not None:
+ v.figure.set_size_inches(20, 12)
+ v.figure.savefig(args.save)
+ elif args.action == "edit":
+ if not cm.can_edit:
+ sys.exit("Sorry, I don't know how to edit the specified colormap")
+ # Hold a reference so it doesn't get GC'ed
+ fig = plt.figure()
+ figureCanvas = gui.FigureCanvas(fig)
+ v = gui.viscm_editor(figure=fig, uniform_space=cm.uniform_space, cmtype=cm.cmtype, method=cm.method, **cm.params)
+ mainwindow = gui.EditorWindow(figureCanvas, v)
+ else:
+ raise RuntimeError("can't happen")
+
+ if args.quit:
+ sys.exit()
+
+ figureCanvas.setSizePolicy(gui.QtWidgets.QSizePolicy.Expanding,
+ gui.QtWidgets.QSizePolicy.Expanding)
+ figureCanvas.updateGeometry()
+
+ mainwindow.resize(800, 600)
+ mainwindow.show()
+
+ # PyQt messes up signal handling by default. Python signal handlers (e.g.,
+ # the default handler for SIGINT that raises KeyboardInterrupt) can only
+ # run when we enter the Python interpreter, which doesn't happen while
+ # idling in the Qt mainloop. (Unless we register a timer to poll
+ # explicitly.) So here we unregister Python's default signal handler and
+ # replace it with... the *operating system's* default signal handler, so
+ # instead of a KeyboardInterrupt our process just exits.
+ import signal
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+ app.exec_()
+
+
+if __name__ == "__main__":
+ cli()
diff --git a/viscm/gui.py b/viscm/gui.py
index ecd3bc6..71e44ce 100644
--- a/viscm/gui.py
+++ b/viscm/gui.py
@@ -948,116 +948,13 @@ def load(self, path):
self.name = path
-def main(argv):
- import argparse
-
- # Usage:
- # python -m viscm
- # python -m viscm edit
- # python -m viscm edit
- # (file.py must define some appropriate globals)
- # python -m viscm view
- # (file.py must define a global named "test_cm")
- # python -m viscm view "matplotlib builtin colormap"
- # python -m viscm view --save=foo.png ...
-
- parser = argparse.ArgumentParser(
- prog="python -m viscm",
- description="A colormap tool.",
- )
- parser.add_argument("action", metavar="ACTION",
- help="'edit' or 'view' (or 'show', same as 'view')",
- choices=["edit", "view", "show"],
- default="edit",
- nargs="?")
- parser.add_argument("colormap", metavar="COLORMAP",
- default=None,
- help="A .json file saved from the editor, or "
- "the name of a matplotlib builtin colormap",
- nargs="?")
- parser.add_argument("--uniform-space", metavar="SPACE",
- default="CAM02-UCS",
- dest="uniform_space",
- help="The perceptually uniform space to use. Usually "
- "you should leave this alone. You can pass 'CIELab' "
- "if you're curious how uniform some colormap is in "
- "CIELab space. You can pass 'buggy-CAM02-UCS' if "
- "you're trying to reproduce the matplotlib colormaps "
- "(which turn out to have had a small bug in the "
- "assumed sRGB viewing conditions) from their bezier "
- "curves.")
- parser.add_argument("-t", "--type", type=str,
- default="linear", choices=["linear", "diverging", "diverging-continuous"],
- help="Choose a colormap type. Supported options are 'linear', 'diverging', and 'diverging-continuous")
- parser.add_argument("-m", "--method", type=str,
- default="CatmulClark", choices=["Bezier", "CatmulClark"],
- help="Choose a spline construction method. 'CatmulClark' is the default, but you may choose the legacy option 'Bezier'")
- parser.add_argument("--save", metavar="FILE",
- default=None,
- help="Immediately save visualization to a file "
- "(view-mode only).")
- parser.add_argument("--quit", default=False, action="store_true",
- help="Quit immediately after starting "
- "(useful with --save).")
- args = parser.parse_args(argv)
-
- cm = Colormap(args.type, args.method, args.uniform_space)
- app = QtWidgets.QApplication([])
-
- if args.colormap:
- cm.load(args.colormap)
-
-
- # Easter egg! I keep typing 'show' instead of 'view' so accept both
- if args.action in ("view", "show"):
- if cm is None:
- sys.exit("Please specify a colormap")
- fig = plt.figure()
- figureCanvas = FigureCanvas(fig)
- v = viscm(cm.cmap, name=cm.name, figure=fig, uniform_space=cm.uniform_space)
- mainwindow = ViewerWindow(figureCanvas, v, cm.name)
- if args.save is not None:
- v.figure.set_size_inches(20, 12)
- v.figure.savefig(args.save)
- elif args.action == "edit":
- if not cm.can_edit:
- sys.exit("Sorry, I don't know how to edit the specified colormap")
- # Hold a reference so it doesn't get GC'ed
- fig = plt.figure()
- figureCanvas = FigureCanvas(fig)
- v = viscm_editor(figure=fig, uniform_space=cm.uniform_space, cmtype=cm.cmtype, method=cm.method, **cm.params)
- mainwindow = EditorWindow(figureCanvas, v)
- else:
- raise RuntimeError("can't happen")
-
- if args.quit:
- sys.exit()
-
- figureCanvas.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
- QtWidgets.QSizePolicy.Expanding)
- figureCanvas.updateGeometry()
-
- mainwindow.resize(800, 600)
- mainwindow.show()
-
- # PyQt messes up signal handling by default. Python signal handlers (e.g.,
- # the default handler for SIGINT that raises KeyboardInterrupt) can only
- # run when we enter the Python interpreter, which doesn't happen while
- # idling in the Qt mainloop. (Unless we register a timer to poll
- # explicitly.) So here we unregister Python's default signal handler and
- # replace it with... the *operating system's* default signal handler, so
- # instead of a KeyboardInterrupt our process just exits.
- import signal
- signal.signal(signal.SIGINT, signal.SIG_DFL)
-
- app.exec_()
-
def about():
QtWidgets.QMessageBox.about(None, "VISCM",
"Copyright (C) 2015-2016 Nathaniel Smith\n" +
"Copyright (C) 2015-2016 Stéfan van der Walt\n"
"Copyright (C) 2016 Hankun Zhao")
+
class ViewerWindow(QtWidgets.QMainWindow):
def __init__(self, figurecanvas, viscm, cmapname, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
@@ -1328,7 +1225,3 @@ def loadviewer(self):
newwindow.resize(800, 600)
newwindow.show()
-
-
-if __name__ == "__main__":
- main(sys.argv[1:])