├── .gitignore
├── CHANGES.rst
├── LICENSE
├── README.md
├── bapt
├── __init__.py
├── cli.py
└── plotting.py
├── examples
├── basic.png
├── basic.yaml
├── command-line.png
├── fade.png
├── fade.yaml
├── flat.png
├── flat.yaml
├── gradients.png
├── gradients.yaml
├── offset.png
└── offset.yaml
├── setup.cfg
├── setup.py
└── tasks.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
--------------------------------------------------------------------------------
/CHANGES.rst:
--------------------------------------------------------------------------------
1 | Change log
2 | ==========
3 |
4 | v1.0.0
5 | -----------
6 | * Initial release of bapt
7 | * Fading, custom gradients, and other options supported
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Alex Ganose
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | README
2 | ======
3 |
4 | Introduction
5 | ------------
6 |
7 | Bapt is a tool for generating publication-ready band alignment plots.
8 |
9 |
10 | Usage
11 | -----
12 |
13 | Bapt can be used via the command-line or python api. For the full
14 | documentation of the command-line flags, please use the built-in help:
15 |
16 | bapt -h
17 |
18 | The bapt command-line can be controlled through command-line flags or
19 | a settings file. The settings file provides considerably more flexibility
20 | for things like custom gradients and fading effects.
21 |
22 | A basic usage of the command-line interface:
23 |
24 | bapt --name "ZnO,MOF-5,HKUST-1,ZIF-8" --ip 7.7,7.3,6.0,6.4 --ea 4.4,2.7,5.1,1.9
25 |
26 | produces a plot that is ready to go into any publication:
27 |
28 |
29 |
30 | A more advanced plot, generated using the `examples/gradients.yaml` config
31 | file, allows for additional effects:
32 |
33 | bapt --filename examples/gradients.yaml
34 |
35 |
36 |
37 | In the alternative case of the relative alignment of bands, without vacuum alignment,
38 | one can specify the band gap values `--band-gap` alongside the valence band offsets `--vbo`,
39 | or equivalently the conduction band offsets `--cbo`:
40 |
41 | bapt -n ZnO,MOF-5,COF-1M --band-gap 1.774,1.366,1.6 --cbo 0.247,-0.4
42 |
43 |
44 |
45 | The band offset approach can also be controlled through a yaml config file. For an example,
46 | see `examples/offset.yml`.
47 |
48 |
49 | Requirements
50 | ------------
51 |
52 | Bapt is currently compatible with Python 2.7 and Python 3.4. Matplotlib is required
53 | for plotting and PyYAML is needed for config files.
54 |
55 | Bapt uses Pip and setuptools for installation. You *probably* already
56 | have this; if not, your GNU/Linux package manager will be able to oblige
57 | with a package named something like ``python-setuptools``. On Max OSX
58 | the Python distributed with [Homebrew]() includes
59 | setuptools and Pip.
60 |
61 |
62 | Installation
63 | ------------
64 |
65 | Bapt is available on PyPI making installation easy:
66 |
67 | pip install --user bapt
68 |
69 | Or:
70 |
71 | pip3 install --user bapt
72 |
73 | To install the python 3 version.
74 |
75 |
76 | Contributors
77 | ------------
78 |
79 | `bapt` was developed by Alex Ganose.
80 |
81 | Other contributions are provided by:
82 |
83 | * Seán Kavanagh through the research groups of David Scanlon at University College London and Aron Walsh at Imperial College London.
84 |
85 |
86 | License
87 | -------
88 |
89 | Bapt is made available under the MIT License.
90 |
--------------------------------------------------------------------------------
/bapt/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | # Copyright (c) Alex Ganose
3 | # Distributed under the terms of the MIT License.
4 |
5 | from .plotting import (pretty_plot, gbar, cbar, vb_cmap, cb_cmap, dashed_arrow, _linewidth, fadebar)
6 |
7 | from matplotlib.ticker import MaxNLocator, MultipleLocator
8 | from matplotlib.colors import LinearSegmentedColormap
9 |
10 |
11 | def get_plot(data, height=5, width=None, emin=None, colours=None,
12 | bar_width=3, show_axis=False, label_size=15, plt=None, gap=0.5,
13 | font=None, show_ea=False, name_colour='w', fade_cb=False, gradients=True, photocat=False):
14 |
15 | width = (bar_width/2. + gap/2.) * len(data) if not width else width
16 | emin = emin if emin else -max([d['ip'] for d in data]) - 2
17 |
18 | plt = pretty_plot(width=width, height=height, plt=plt, fonts=[font])
19 | ax = plt.gca()
20 |
21 | pad = 2. / emin
22 | for i, compound in enumerate(data):
23 | x = i * (bar_width + gap)
24 | ip = -compound['ip']
25 | ea = -compound['ea']
26 |
27 | fade = 'fade' in compound and compound['fade']
28 | edge_c_cb = '#808080' if fade or fade_cb else 'k'
29 | edge_c_vb = '#808080' if fade else 'k'
30 | edge_z = 4 if fade else 5
31 |
32 | if gradients:
33 | vg = vb_cmap if 'vb_gradient' not in compound else \
34 | compound['vb_gradient']
35 | cg = cb_cmap if 'cb_gradient' not in compound else \
36 | compound['cb_gradient']
37 |
38 | gbar(ax, x, ip, bottom=emin, bar_width=bar_width, show_edge=True,
39 | gradient=vg, edge_colour=edge_c_vb, edge_zorder=edge_z)
40 | gbar(ax, x, ea, bar_width=bar_width, show_edge=True,
41 | gradient=cg, edge_colour=edge_c_cb, edge_zorder=edge_z)
42 |
43 | else:
44 | vc = '#219ebc' if 'vb_colour' not in compound else \
45 | compound['vb_colour']
46 | cc ='#fb8500' if 'cb_colour' not in compound else \
47 | compound['cb_colour']
48 |
49 | cbar(ax, x, ip, vc, bottom=emin, bar_width=bar_width, show_edge=True,
50 | edge_colour=edge_c_vb, edge_zorder=edge_z)
51 | cbar(ax, x, ea, cc, bar_width=bar_width, show_edge=True,
52 | edge_colour=edge_c_vb, edge_zorder=edge_z)
53 |
54 | if show_ea:
55 | dashed_arrow(ax, x + bar_width/6., ea - pad/3, 0,
56 | -ea + 2 * pad/3, colour='k', line_width=_linewidth)
57 | dashed_arrow(ax, x + bar_width/6., ip - pad/3, 0,
58 | ea-ip + 2 * pad/3, colour='k', end_head=False,
59 | line_width=_linewidth)
60 | ax.text(x + bar_width/4., ip - pad/2,
61 | '{:.1f} eV'.format(compound['ip']), ha='left',
62 | va='bottom', size=label_size, color='k', zorder=2)
63 | ax.text(x + bar_width/4., pad * 2,
64 | '{:.1f} eV'.format(compound['ea']), ha='left', va='top',
65 | size=label_size, color='k', zorder=2)
66 | else:
67 | dashed_arrow(ax, x + bar_width/6., ip - pad/3, 0,
68 | -ip + 2 * pad/3, colour='k', line_width=_linewidth)
69 | ax.text(x + bar_width/4., pad * 2,
70 | '{:.1f} eV'.format(compound['ip']), ha='left', va='top',
71 | size=label_size, color='k', zorder=2)
72 |
73 | ax.text(x + bar_width/2., ip + pad, compound['name'], zorder=2,
74 | ha='center', va='top', size=label_size, color=name_colour)
75 |
76 | if fade:
77 | fadebar(ax, x, emin, bar_width=bar_width, bottom=0)
78 | elif fade_cb:
79 | fadebar(ax, x, ea, bar_width=bar_width, bottom=0, zorder=1)
80 |
81 | ax.set_ylim((emin, 0))
82 | ax.set_xlim((0, (len(data) * bar_width) + ((len(data) - 1) * gap)))
83 |
84 | if photocat:
85 | end = (len(data) * bar_width) + ((len(data) - 1) * gap)
86 | ax.hlines([-4.44, -5.67], 0, end, colors=['#808080', '#808080'], zorder=0, linewidths=1, linestyles='dotted', label=['H3O$^+$/H2', 'H$_2$O/O$_2$'])
87 | plt.text(end+0.1, -4.44, '[H$^+$/H$_2$]', va='center', size=label_size)
88 | plt.text(end+0.1, -5.67, '[H$_2$O/O$_2$]', va='center', size=label_size)
89 |
90 | ax.set_xticks([])
91 |
92 | if show_axis:
93 | ax.set_ylabel("Energy (eV)", size=label_size)
94 | ax.yaxis.set_major_locator(MaxNLocator(5))
95 | for spine in ax.spines.values():
96 | spine.set_zorder(5)
97 | else:
98 | for spine in ax.spines.values():
99 | spine.set_visible(False)
100 | ax.yaxis.set_visible(False)
101 |
102 | ax.set_title('Vacuum Level', size=label_size)
103 | ax.set_xlabel('Valence Band', size=label_size)
104 | return plt
105 |
106 |
107 | def read_config(filename):
108 | import yaml
109 |
110 | with open(filename, 'r') as f:
111 | config = yaml.safe_load(f)
112 |
113 | settings = config['settings'] if 'settings' in config else {}
114 | gradient_data = config['gradients'] if 'gradients' in config else []
115 | gradients = {}
116 | for d in gradient_data:
117 | g = LinearSegmentedColormap.from_list(d['id'], [d['start'], d['end']],
118 | N=200)
119 | gradients[d['id']] = g
120 |
121 | band_edge_data = config['compounds']
122 | for compound in band_edge_data:
123 | if 'gradient' in compound:
124 | ids = list(map(int, compound['gradient'].split(',')))
125 | compound.pop('gradient', None)
126 | if len(ids) == 1:
127 | compound['vb_gradient'] = gradients[ids[0]]
128 | compound['cb_gradient'] = gradients[ids[0]]
129 | else:
130 | compound['vb_gradient'] = gradients[ids[0]]
131 | compound['cb_gradient'] = gradients[ids[1]]
132 | return band_edge_data, settings
133 |
134 |
135 | def get_plot_novac(data, height=5, width=None, emin=None, emax=None,
136 | colours=None, bar_width=3, show_axis=False, hide_cbo=False,
137 | hide_vbo=False, label_size=15, plt=None, gap=0.5, font=None,
138 | show_ea=False, name_colour='w', fade_cb=False, gradients=True):
139 |
140 | width = (bar_width/2. + gap/2.) * len(data) if not width else width
141 | emin = emin if emin else min([d['vbo'] for d in data]) - 2
142 | emax = emax if emax else max([d['vbo'] + d['band_gap'] for d in data]) + 2
143 |
144 | plt = pretty_plot(width=width, height=height, plt=plt, fonts=[font])
145 | ax = plt.gca()
146 |
147 | pad = - (emax - emin) / 20
148 | for i, compound in enumerate(data):
149 | x = i * (bar_width + gap)
150 | ip = compound['vbo']
151 | ea = compound['vbo'] + compound['band_gap']
152 |
153 | fade = 'fade' in compound and compound['fade']
154 | edge_c_cb = '#808080' if fade or fade_cb else 'k'
155 | edge_c_vb = '#808080' if fade else 'k'
156 | edge_z = 4 if fade else 5
157 |
158 | if gradients:
159 | vc = vb_cmap if 'vb_gradient' not in compound else \
160 | compound['vb_gradient']
161 | cc = cb_cmap if 'cb_gradient' not in compound else \
162 | compound['cb_gradient']
163 |
164 | gbar(ax, x, ip, bottom=emin, bar_width=bar_width, show_edge=True,
165 | gradient=vc, edge_colour=edge_c_vb, edge_zorder=edge_z)
166 | gbar(ax, x, ea, bottom=emax, bar_width=bar_width, show_edge=True,
167 | gradient=cc, edge_colour=edge_c_cb, edge_zorder=edge_z)
168 | else:
169 | vc = '#219ebc' if 'vb_colour' not in compound else \
170 | compound['vb_colour']
171 | cc ='#fb8500' if 'cb_colour' not in compound else \
172 | compound['cb_colour']
173 |
174 | cbar(ax, x, ip, vc, bottom=emin, bar_width=bar_width, show_edge=True,
175 | edge_colour=edge_c_vb, edge_zorder=edge_z)
176 | cbar(ax, x, ea, cc, bottom=emax, bar_width=bar_width, show_edge=True,
177 | edge_colour=edge_c_vb, edge_zorder=edge_z)
178 |
179 | dashed_arrow(ax, x + bar_width/6., ip - pad/3, 0,
180 | ea-ip + 2 * pad/3, colour='k', line_width=_linewidth)
181 | ax.text(x + bar_width/4., ip + compound['band_gap']/2,
182 | '{:.2f} eV'.format(compound['band_gap']), ha='left',
183 | va='center', size=label_size, color='k', zorder=2)
184 |
185 | t = ax.text(x + bar_width/2., ip + pad / 2, compound['name'], zorder=2,
186 | ha='center', va='top', size=label_size, color=name_colour)
187 |
188 | # use renderer to get position of compound label text
189 | renderer = plt.gcf().canvas.get_renderer()
190 | bb = t.get_window_extent(renderer=renderer)
191 | inv = ax.transData.inverted()
192 | y1 = inv.transform([bb.y0, bb.y1 + 2 * bb.height])[1]
193 | if i > 0:
194 | if not hide_vbo:
195 | vbo = compound['vbo'] - data[i-1]['vbo']
196 | ax.text(x + bar_width/2., y1,
197 | "{:+.2f} eV".format(vbo), zorder=2, ha='center',
198 | va='top', size=label_size, color=name_colour)
199 |
200 | if not hide_cbo:
201 | cbo = compound['cbo'] - data[i-1]['cbo']
202 | ax.text(x + bar_width/2., ea - pad / 4,
203 | "{:+.2f} eV".format(cbo), zorder=2, ha='center',
204 | va='bottom', size=label_size, color=name_colour)
205 |
206 | if fade:
207 | fadebar(ax, x, emin, bar_width=bar_width, bottom=emax)
208 | elif fade_cb:
209 | fadebar(ax, x, ea, bar_width=bar_width, bottom=emax, zorder=1)
210 |
211 | ax.set_ylim((emin, emax))
212 | ax.set_xlim((0, (len(data) * bar_width) + ((len(data) - 1) * gap)))
213 | ax.set_xticks([])
214 |
215 | if show_axis:
216 | ax.set_ylabel("Energy (eV)", size=label_size)
217 | ax.yaxis.set_major_locator(MultipleLocator(1))
218 | for spine in ax.spines.values():
219 | spine.set_zorder(5)
220 | ax.tick_params(which='major', width=_linewidth)
221 | ax.tick_params(which='minor', right='on')
222 | ax.yaxis.set_minor_locator(MultipleLocator(0.5))
223 | else:
224 | for spine in ax.spines.values():
225 | spine.set_visible(False)
226 | ax.yaxis.set_visible(False)
227 |
228 | ax.set_title('Conduction Band', size=label_size)
229 | ax.set_xlabel('Valence Band', size=label_size)
230 | return plt
231 |
--------------------------------------------------------------------------------
/bapt/cli.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | # Copyright (c) Alex Ganose
3 | # Distributed under the terms of the MIT License.
4 |
5 | import sys
6 | import argparse
7 |
8 | from . import read_config, get_plot, get_plot_novac
9 |
10 | __author__ = "Alex Ganose"
11 | __version__ = "0.1"
12 | __maintainer__ = "Alex Ganose"
13 | __email__ = "alexganose@googlemail.com"
14 | __date__ = "Oct 19, 2017"
15 |
16 |
17 | def main():
18 | parser = argparse.ArgumentParser(description="""
19 | Plotter for electronic band alignment diagrams.""",
20 | epilog="""
21 | Author: {}
22 | Version: {}
23 | Last updated: {}""".format(__author__, __version__, __date__))
24 | parser.add_argument('-f', '--filename', default=None,
25 | help='Path to file containing alignment information.')
26 | parser.add_argument('-n', '--name',
27 | help='List of compound names (comma seperated). ' +
28 | 'Must be used in conguction with --ip and --ea. ' +
29 | 'Use $_x$ and $^y$ for subscript and superscript.')
30 | parser.add_argument('-i', '--ip',
31 | help='List of ionisation potentials (comma separated).')
32 | parser.add_argument('-e', '--ea',
33 | help='List of electron affinities (comma separated).')
34 | parser.add_argument('-c', '--cbo', default=None,
35 | help='List of conduction band offsets (comma separated). ' +
36 | '(Relative to first compound)(-> No vacuum alignment)')
37 | parser.add_argument('-v', '--vbo', default=None,
38 | help='List of valence band offsets (comma separated). ' +
39 | '(Relative to first compound)(-> No vacuum alignment)')
40 | parser.add_argument('-b', '--band-gap', dest='band_gap',
41 | help='List of band gaps (comma separated).')
42 | parser.add_argument('-o', '--output', default='alignment.pdf',
43 | help='Output file name (defaults to alignment.pdf).')
44 | parser.add_argument('--show-ea', action='store_true', dest='show_ea',
45 | help='Display the electron affinity value.')
46 | parser.add_argument('--hide-cbo', action='store_true', dest='hide_cbo',
47 | help='Hide the conduction band offsets.')
48 | parser.add_argument('--hide-vbo', action='store_true', dest='hide_vbo',
49 | help='Hide the valence band offsets.')
50 | parser.add_argument('--show-axis', action='store_true', dest='show_axis',
51 | help='Display the energy yaxis bar and label.')
52 | parser.add_argument('--height', type=float, default=5,
53 | help='Set figure height in inches.')
54 | parser.add_argument('--width', type=float, default=None,
55 | help='Set figure width in inches.')
56 | parser.add_argument('--emin', type=float, default=None,
57 | help='Set energy minium on y axis.')
58 | parser.add_argument('--gap', type=float, default=0,
59 | help='Set gap between bars.')
60 | parser.add_argument('--bar-width', type=float, dest='bar_width', default=3,
61 | help='Set the width per bar for each compound.')
62 | parser.add_argument('--font', default=None, help='Font to use.')
63 | parser.add_argument('--font-size', type=float, dest='label_size',
64 | default=15, help='Set font size all labels.')
65 | parser.add_argument('--name-colour', dest='name_colour', default='w',
66 | help='Set the colour for the compound name.')
67 | parser.add_argument('--fade-cb', action='store_true', dest='fade_cb',
68 | help='Apply a fade to the conduction band segments.')
69 | parser.add_argument('--dpi', default=400,
70 | help='Dots-per-inch for file output.')
71 | parser.add_argument('--no-gradient', action='store_false', dest='gradients',
72 | help='Plot the boxes as solid colours.')
73 | parser.add_argument('--photocat', action='store_true',
74 | help='Plot water redox potentials')
75 | args = parser.parse_args()
76 |
77 | emsg = None
78 | if not args.filename and not (args.name or args.ip or args.ea or args.band_gap or args.cbo or args.vbo):
79 | emsg = "ERROR: no arguments specified."
80 | elif not args.filename and not (args.ip or args.ea) and \
81 | not (args.name and args.band_gap and (args.cbo or args.vbo)):
82 | emsg = "ERROR: --name, --band-gap and --cbo or --vbo flags must specified concurrently."
83 | elif not args.filename and not (args.cbo or args.vbo or args.band_gap) and \
84 | not (args.name and args.ip and args.ea):
85 | emsg = "ERROR: --name, --ip and --ea flags must specified concurrently."
86 | elif not args.filename and (args.cbo and args.vbo):
87 | emsg = "ERROR: cbo and vbo specified simultaneously."
88 | elif args.filename and (args.name or args.ip or args.ea or args.band_gap or args.cbo or args.vbo):
89 | emsg = "ERROR: filename and name/ip/ea/cbo/vbo specified simultaneously."
90 |
91 | if emsg:
92 | print(emsg)
93 | sys.exit()
94 |
95 | output_file = args.output
96 |
97 | if args.filename:
98 | data, settings = read_config(args.filename)
99 | for item in data:
100 | if 'cbo' in item:
101 | item['vbo'] = data[0]['band_gap'] - item['band_gap'] + item['cbo']
102 | if 'vbo' in item:
103 | item['cbo'] = -data[0]['band_gap'] + item['band_gap'] + item['vbo']
104 |
105 | else:
106 | for k, v in {'cbo': args.cbo, 'vbo': args.vbo}.items():
107 | if v:
108 | data = [{'name': name, 'band_gap': band_gap, k: c_or_v_bo} for name, band_gap, c_or_v_bo in
109 | zip(args.name.split(','), map(float, args.band_gap.split(',')),
110 | [0] + list(map(float, v.split(','))))]
111 | for item in data:
112 | if k == 'cbo':
113 | item['vbo'] = data[0]['band_gap'] - item['band_gap'] + item['cbo']
114 | if k == 'vbo':
115 | item['cbo'] = -data[0]['band_gap'] + item['band_gap'] + item['vbo']
116 | if args.ip:
117 | data = [{'name': name, 'ip': ip, 'ea': ea} for name, ip, ea in
118 | zip(args.name.split(','), map(float, args.ip.split(',')),
119 | map(float, args.ea.split(',')))]
120 |
121 | settings = {}
122 |
123 | properties = vars(args)
124 | remove_keys = ('filename', 'ip', 'ea', 'band_gap', 'cbo',
125 | 'vbo', 'name', 'output', 'dpi')
126 | for key in remove_keys:
127 | properties.pop(key, None)
128 | properties.update(settings)
129 |
130 | if 'vbo' in data[0]: # no vacuum alignment
131 | [properties.pop(key, None) for key in ['photocat_hlines', 'photocat']]
132 | plt = get_plot_novac(data, **properties)
133 | else:
134 | [properties.pop(key, None) for key in ['hide_cbo', 'hide_vbo']]
135 | plt = get_plot(data, **properties)
136 | plt.savefig(output_file, dpi=400, bbox_inches='tight')
137 |
138 |
139 | if __name__ == "__main__":
140 | main()
141 |
--------------------------------------------------------------------------------
/bapt/plotting.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | # Copyright (c) Alex Ganose
3 | # Distributed under the terms of the MIT License.
4 |
5 | from matplotlib.patches import Rectangle
6 | from matplotlib.colors import LinearSegmentedColormap
7 |
8 |
9 | cb_colours = [(247/255., 148/255., 51/255.), (251/255., 216/255., 181/255.)]
10 | vb_colours = [(23/255., 71/255., 158/255.), (174/255., 198/255., 242/255.)]
11 | cb_cmap = LinearSegmentedColormap.from_list('cb', cb_colours, N=200)
12 | vb_cmap = LinearSegmentedColormap.from_list('vb', vb_colours, N=200)
13 |
14 | default_fonts = ['Whitney Pro', 'Helvetica', 'Arial', 'Whitney Book'
15 | 'Liberation Sans', 'Andale Sans']
16 | _ticklabelsize = 15
17 | _labelsize = 18
18 | _ticksize = 5
19 | _linewidth = 1.
20 |
21 |
22 | def pretty_plot(width=5, height=5, plt=None, dpi=400, fonts=None):
23 | """Initialise a matplotlib plot with sensible defaults for publication.
24 |
25 |
26 | Args:
27 | width (float): Width of plot in inches. Defaults to 8 in.
28 | height (float): Height of plot in inches. Defaults to 8 in.
29 | plt (matplotlib.pyplot): If plt is supplied, changes will be made to an
30 | existing plot. Otherwise, a new plot will be created.
31 | dpi (int): Sets dot per inch for figure. Defaults to 400.
32 | fonts (list): A list of preferred fonts. If these are not found the
33 | default fonts will be used.
34 |
35 | Returns:
36 | Matplotlib plot object with properly sized fonts.
37 | """
38 |
39 | from matplotlib import rc
40 |
41 | if plt is None:
42 | import matplotlib.pyplot as plt
43 | plt.figure(figsize=(width, height), facecolor="w", dpi=dpi)
44 | ax = plt.gca()
45 |
46 | ax = plt.gca()
47 |
48 | ax.tick_params(width=_linewidth, size=_ticksize)
49 | ax.tick_params(which='major', size=_ticksize, width=_linewidth,
50 | labelsize=_ticklabelsize, pad=4, direction='in',
51 | top='off', bottom='off', right='on', left='on')
52 | ax.tick_params(which='minor', size=_ticksize/2, width=_linewidth,
53 | direction='in', top='off', bottom='off')
54 |
55 | ax.set_title(ax.get_title(), size=20)
56 | for axis in ['top', 'bottom', 'left', 'right']:
57 | ax.spines[axis].set_linewidth(_linewidth)
58 |
59 | ax.set_xlabel(ax.get_xlabel(), size=_labelsize)
60 | ax.set_ylabel(ax.get_ylabel(), size=_labelsize)
61 |
62 | fonts = default_fonts if fonts is None or fonts == [None] else fonts + default_fonts
63 |
64 | rc('font', **{'family': 'sans-serif', 'sans-serif': fonts})
65 | rc('text', usetex=False)
66 | rc('pdf', fonttype=42)
67 | rc('mathtext', fontset='stixsans')
68 | rc('legend', handlelength=2)
69 | return plt
70 |
71 |
72 | def cbar(ax, left, top, face_colour, bar_width=3, bottom=0,
73 | show_edge=True, edge_colour='k', edge_zorder=5):
74 | X = [[.6, .6], [.7, .7]]
75 | right = left + bar_width
76 | patch = Rectangle((left, top), bar_width, bottom-top, fill=True,
77 | clip_on=False, facecolor=face_colour,
78 | )
79 | ax.add_patch(patch)
80 |
81 | if show_edge:
82 | border = Rectangle((left, top), bar_width, bottom-top, fill=False,
83 | lw=_linewidth, edgecolor=edge_colour, clip_on=False,
84 | zorder=edge_zorder)
85 | ax.add_patch(border)
86 |
87 | def gbar(ax, left, top, bar_width=3, bottom=0, gradient=vb_cmap,
88 | show_edge=True, edge_colour='k', edge_zorder=5):
89 | X = [[.6, .6], [.7, .7]]
90 | right = left + bar_width
91 | ax.imshow(X, interpolation='bicubic', cmap=gradient,
92 | extent=(left, right, bottom, top), alpha=1)
93 |
94 | if show_edge:
95 | border = Rectangle((left, top), bar_width, bottom-top, fill=False,
96 | lw=_linewidth, edgecolor=edge_colour, clip_on=False,
97 | zorder=edge_zorder)
98 | ax.add_patch(border)
99 |
100 |
101 | def fadebar(ax, left, top, bar_width=3, bottom=0, zorder=3):
102 | fade = Rectangle((left, top), bar_width, bottom-top, alpha=0.5, color='w',
103 | clip_on=False, zorder=zorder)
104 | ax.add_patch(fade)
105 |
106 |
107 | def dashed_arrow(ax, x, y, dx, dy, colour='k', line_width=_linewidth,
108 | start_head=True, end_head=True):
109 | length = 0.25
110 | width = 0.2
111 | ax.plot([x, x + dx], [y, y + dy], c=colour, ls='--', lw=line_width,
112 | dashes=(8, 4.3))
113 | if start_head:
114 | ax.arrow(x, y + length, 0, -length, head_width=width,
115 | head_length=length, fc=colour, ec=colour, overhang=0.15,
116 | length_includes_head=True, lw=line_width)
117 | if end_head:
118 | ax.arrow(x + dx, y + dy - length, 0, length, head_width=width,
119 | head_length=length, fc=colour, ec=colour, overhang=0.15,
120 | length_includes_head=True, lw=line_width)
121 |
--------------------------------------------------------------------------------
/examples/basic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/utf/bapt/c6c94732f56e6a68b4bb26417880ff58ff49b7ce/examples/basic.png
--------------------------------------------------------------------------------
/examples/basic.yaml:
--------------------------------------------------------------------------------
1 | compounds:
2 | - name: 'ZnO'
3 | ea: 4.4
4 | ip: 7.7
5 | - name: 'MOF-5'
6 | ea: 2.7
7 | ip: 9
8 | - name: 'HKUST-1'
9 | ea: 5.1
10 | ip: 6.0
11 | - name: 'ZIF-8'
12 | ea: 1.9
13 | ip: 6.4
14 | - name: 'COF-1M'
15 | ea: 1.3
16 | ip: 4.7
17 |
--------------------------------------------------------------------------------
/examples/command-line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/utf/bapt/c6c94732f56e6a68b4bb26417880ff58ff49b7ce/examples/command-line.png
--------------------------------------------------------------------------------
/examples/fade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/utf/bapt/c6c94732f56e6a68b4bb26417880ff58ff49b7ce/examples/fade.png
--------------------------------------------------------------------------------
/examples/fade.yaml:
--------------------------------------------------------------------------------
1 | compounds:
2 | - name: 'ZnO'
3 | ea: 4.4
4 | ip: 7.7
5 | fade: True
6 | - name: 'MOF-5'
7 | ea: 2.7
8 | ip: 7.3
9 | fade: True
10 | - name: 'HKUST-1'
11 | ea: 5.1
12 | ip: 6.0
13 | - name: 'ZIF-8'
14 | ea: 1.9
15 | ip: 6.4
16 | fade: True
17 | - name: 'COF-1M'
18 | ea: 1.3
19 | ip: 4.7
20 | fade: True
21 |
--------------------------------------------------------------------------------
/examples/flat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/utf/bapt/c6c94732f56e6a68b4bb26417880ff58ff49b7ce/examples/flat.png
--------------------------------------------------------------------------------
/examples/flat.yaml:
--------------------------------------------------------------------------------
1 | compounds:
2 | - name: 'ZnO'
3 | ea: 4.4
4 | ip: 7.7
5 | cb_colour: '#FDD968'
6 | vb_colour: '#B36AAE'
7 | - name: 'MOF-5'
8 | ea: 2.7
9 | ip: 7.3
10 | cb_colour: '#FDD968'
11 | vb_colour: '#B36AAE'
12 | - name: 'HKUST-1'
13 | ea: 5.1
14 | ip: 6.0
15 | cb_colour: '#FDD968'
16 | vb_colour: '#B36AAE'
17 | - name: 'ZIF-8'
18 | ea: 1.9
19 | ip: 6.4
20 | cb_colour: '#FFEEB8'
21 | vb_colour: '#ECCDE9'
22 | - name: 'COF-1M'
23 | ea: 1.3
24 | ip: 4.7
25 | cb_colour: '#FFEEB8'
26 | vb_colour: '#ECCDE9'
27 |
28 | settings:
29 | show_ea : True
30 | photocat: True
31 | gradients: False
32 | show_axis: True
--------------------------------------------------------------------------------
/examples/gradients.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/utf/bapt/c6c94732f56e6a68b4bb26417880ff58ff49b7ce/examples/gradients.png
--------------------------------------------------------------------------------
/examples/gradients.yaml:
--------------------------------------------------------------------------------
1 | compounds:
2 | - name: 'ZnO'
3 | ea: 4.4
4 | ip: 7.7
5 | gradient: 1, 0
6 | - name: 'MOF-5'
7 | ea: 2.7
8 | ip: 7.3
9 | gradient: 0, 1
10 | - name: 'HKUST-1'
11 | ea: 5.1
12 | ip: 6.0
13 | gradient: 1, 0
14 | - name: 'ZIF-8'
15 | ea: 1.9
16 | ip: 6.4
17 | gradient: 0, 1
18 | - name: 'COF-1M'
19 | ea: 1.3
20 | ip: 4.7
21 | gradient: 1, 0
22 |
23 | gradients:
24 | - id: 0
25 | start: '#FFFFFF'
26 | end: '#000000'
27 | - id: 1
28 | start: '#FFFFFF'
29 | end: '#FFC116'
30 |
31 | settings:
32 | name_colour: 'k'
33 | fade_cb: True
34 | show_ea: True
35 | show_axis: True
36 |
--------------------------------------------------------------------------------
/examples/offset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/utf/bapt/c6c94732f56e6a68b4bb26417880ff58ff49b7ce/examples/offset.png
--------------------------------------------------------------------------------
/examples/offset.yaml:
--------------------------------------------------------------------------------
1 | compounds:
2 | - name: ZnO
3 | band_gap: 1.774
4 | cbo: 0
5 | - name: MOF-5
6 | band_gap: 1.366
7 | cbo: 0.247
8 | - name: COF-1M
9 | band_gap: 1.6
10 | cbo: -0.4
11 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | description-file = README.md
3 |
4 | [bdist_wheel]
5 | universal = 1
6 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | """
2 | Vaspy: SMTG utils for working with Vasp
3 | """
4 |
5 | from os.path import abspath, dirname
6 | from setuptools import setup, find_packages
7 |
8 | project_dir = abspath(dirname(__file__))
9 |
10 | setup(
11 | name='bapt',
12 | version='1.1.0',
13 | description='Band alignment plotting tool',
14 | long_description="""
15 | Get yourself some nice band alignment diagrams
16 | """,
17 | url="https://github.com/utf/bapt",
18 | author="Alex Ganose",
19 | author_email="alexganose@googlemail.com",
20 | license='MIT',
21 |
22 | classifiers=[
23 | 'Development Status :: 5 - Production/Stable',
24 | 'Intended Audience :: Science/Research',
25 | 'License :: OSI Approved :: MIT License',
26 | 'Natural Language :: English',
27 | 'Programming Language :: Python :: 2.7',
28 | 'Programming Language :: Python :: 3',
29 | 'Programming Language :: Python :: 3.3',
30 | 'Programming Language :: Python :: 3.4',
31 | 'Programming Language :: Python :: 3.5',
32 | 'Topic :: Scientific/Engineering :: Chemistry',
33 | 'Topic :: Scientific/Engineering :: Physics'
34 | ],
35 | keywords='chemistry dft band alignment ionisation potential electron',
36 | packages=find_packages(),
37 | install_requires=['matplotlib', 'PyYAML>=5.1'],
38 | entry_points={'console_scripts': ['bapt = bapt.cli:main']}
39 | )
40 |
--------------------------------------------------------------------------------
/tasks.py:
--------------------------------------------------------------------------------
1 | from invoke import task
2 |
3 | import os
4 | import json
5 | import requests
6 | import re
7 |
8 |
9 | """
10 | Deployment file to facilitate releases of bapt.
11 | Note that this file is meant to be run from the root directory of the repo.
12 | """
13 |
14 | __author__ = "Alex Ganose"
15 | __email__ = "alexganose@googlemail.com"
16 | __date__ = "Oct 20 2017"
17 |
18 |
19 | @task
20 | def publish(ctx):
21 | ctx.run("rm dist/*.*", warn=True)
22 | ctx.run("python setup.py sdist bdist_wheel")
23 | ctx.run("twine upload dist/*")
24 |
25 |
26 | @task
27 | def release(ctx):
28 | with open("CHANGES.rst") as f:
29 | contents = f.read()
30 | toks = re.split("\-+", contents)
31 | new_ver = re.findall('\n(v.*)', contents)[0]
32 | desc = toks[1].strip()
33 | toks = desc.split("\n")
34 | desc = "\n".join(toks[:-1]).strip()
35 | payload = {
36 | "tag_name": new_ver,
37 | "target_commitish": "master",
38 | "name": new_ver,
39 | "body": desc,
40 | "draft": False,
41 | "prerelease": False
42 | }
43 | response = requests.post(
44 | "https://api.github.com/repos/utf/bapt/releases",
45 | data=json.dumps(payload),
46 | headers={"Authorization": "token " + os.environ["GITHUB_TOKEN"]})
47 | print(response.text)
48 |
--------------------------------------------------------------------------------