-
Notifications
You must be signed in to change notification settings - Fork 3
/
write_hfiles
215 lines (179 loc) · 7.25 KB
/
write_hfiles
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#!/usr/bin/env python3
#============================================================
# write_hfiles
# Copyright (C) 2022 Thomas Lavergne
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#============================================================
import sys
import os
from glob import glob
from datetime import datetime
# Import python modules holding colormaps
try:
# https://matplotlib.org/stable/tutorials/colors/colormaps.html
from matplotlib import cm
from matplotlib import pylab
has_mlib = True
except ImportError:
has_mlib = False
try:
# https://matplotlib.org/cmocean
import cmocean
has_cmocean = True
except ImportError:
has_cmocean = False
try:
# https://www.fabiocrameri.ch/colourmaps
# https://pypi.org/project/cmcrameri
import cmcrameri
has_cmcrameri = True
except ImportError:
has_cmcrameri = False
try:
# https://cmasher.readthedocs.io/index.html
import cmasher as cmr
from cmasher import cm as cmrcm
has_cmasher = True
except ImportError:
has_cmasher = False
# We could probaby do without numpy, but it is convenient
import numpy as np
def write_one_hfile(cmap, name, odir):
''' Write a colormap into a .h file to be included in the ncview source code. '''
x = np.arange(0,256) / 255.
f = 255 * cmap(x)
fname = 'colormaps_' + name + '.h'
fname = os.path.join(odir,fname)
if not os.path.exists(odir):
os.makedirs(odir)
print("Make directory {}".format(odir,))
g = f[:,:3].flatten().astype('int')
G = ','.join(['{}'.format(gi) for gi in g])
print("Write {}".format(fname,))
with open(fname,'w') as _ :
_.write('// Generated by write_hfiles from package ncmaps\n')
_.write('\n')
_.write('static int cmap_{}[] = {{\n'.format(name))
_.write(G + "\n")
_.write("};\n")
def write_mlib_cmaps(odir, ):
''' Write the colormaps from matplotlib. '''
# Perceptually Uniform Sequential colormaps
cmaps = ['viridis', 'inferno', 'magma', 'plasma', 'cividis']
# Add some more colormaps (diverging and cyclic)
cmaps.extend(['PiYG', 'PRGn', 'RdBu', 'coolwarm', 'bwr', 'twilight', 'twilight_shifted'])
for cmap in cmaps:
cmo = pylab.get_cmap(cmap)
write_one_hfile(cmo, cmap, odir)
return cmaps
def write_cmocean_cmaps(odir,):
''' Write the colormaps from cmocean. '''
cmaps = cmocean.cm.cmapnames
for cmap in cmaps:
cmo = cmocean.cm.cmap_d[cmap]
write_one_hfile(cmo, cmap, odir)
return cmaps
def write_cmcrameri_cmaps(odir,):
''' Write the colormaps from cmcrameri. '''
try:
# old interface (at least before 1.4)
cmap_dict = cmcrameri.cm.crameri_cmap
except AttributeError:
cmap_dict = cmcrameri.cm.cmaps
cmaps = [cma for cma in cmap_dict.keys() if not cma.endswith('_r') and not cma.endswith('S')]
for cmap in cmaps:
cmo = cmap_dict[cmap]
write_one_hfile(cmo, cmap, odir)
return cmaps
def write_cmasher_cmaps(odir,):
''' Write the colomaps from cmasher. '''
all_cmaps = []
for cmtype in ('sequential', 'diverging', 'cyclic'):
cmaps = [ t for t in cmrcm.cmap_cd[cmtype].keys() if not t.endswith('_r')]
for cmap in cmaps:
cmo = cmrcm.cmap_cd[cmtype][cmap]
write_one_hfile(cmo, cmap, odir)
all_cmaps.extend(cmaps,)
return all_cmaps
if __name__ == '__main__':
import argparse
from argparse import RawDescriptionHelpFormatter
# Get commandline parameters
p = argparse.ArgumentParser("write_hfiles", formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Prepare scientific colormaps as .h files so that they can be compiled into ncview.')
p.add_argument('--dir', help='Directory where to write the colormaps.', required=True)
args = p.parse_args()
# Use the full path to the output directory
args.dir = os.path.realpath(args.dir)
if not has_mlib and not has_cmocean and not has_cmcrameri:
sys.exit("Found no colormap to write.")
# write all the .ncmaps files
all_cmaps = []
if has_mlib:
all_cmaps.extend(write_mlib_cmaps(args.dir,))
else:
print("Skip colormaps from matplotlib (module not found).")
if has_cmocean:
all_cmaps.extend(write_cmocean_cmaps(args.dir,))
else:
print("Skip colormaps from cmocean (module not found).")
if has_cmcrameri:
all_cmaps.extend(write_cmcrameri_cmaps(args.dir,))
else:
print("Skip colormaps from cmcrameri (module not found).")
# In ncview (Ncview 2.1.8 David W. Pierce 8 March 2017)
# a bug is triggered if the number of colormaps available
# to ncview through NCVIEWBASE is larger than 79.
# (see https://github.com/TomLav/ncmaps/issues/5#issuecomment-832060948)
#
# We can thus not support the cmasher colormaps at present. The code
# to handler cmasher is kept but de-activated.
#
#if has_cmasher:
# all_cmaps.extend(write_cmasher_cmaps(args.dir,))
#else:
# print("Skip colormaps from cmasher (module not found).")
# Last step is to generate file colormaps_ncmaps.h, to be placed in ncview-ncmaps src/
# First load which ncmaps are available as .h files
patt = os.path.join(args.dir,'*.h')
list_ncmap_files = glob(patt)
if len(patt) == 0:
sys.exit("Internal error: cannot find the .h files we just wrote.")
ncmaps_in_dir = []
for ncmap_file in list_ncmap_files:
ncf = os.path.basename(ncmap_file)
ncmaps_in_dir.append(ncf.replace('.h','').replace('colormaps_',''))
# This sort() will make the colormaps to be listed alphabetically
# in the .ncviewrc file (and thus ncview).
ncmaps_in_dir.sort(key=str.lower)
fname = os.path.join('.','colormaps_ncmaps.h') # we place the file in '.'
with open(fname, 'w') as _:
# write header
_.write('// Colormaps provided by ncmaps - {}\n'.format(datetime.utcnow().isoformat()))
_.write('\n')
# write include statements
for cmap in ncmaps_in_dir:
# #include "colormaps/colormaps_batlow.h"
_.write('#include "colormaps/colormaps_{}.h"\n'.format(cmap))
_.write('\n')
# write the INIT_NCMAPS_CMAPS statement
_.write('#define INIT_NCMAPS_CMAPS \\\n')
for cmap in ncmaps_in_dir:
last_slash = '\\'
if cmap == ncmaps_in_dir[-1]:
last_slash = ''
_.write('init_cmap_from_data( "{n:}", cmap_{n:} ); {s:}\n'.format(n=cmap, s=last_slash))
sys.exit('Success, the .h files are in {}'.format(args.dir,))