def import_cmaps(cmap_path): """ Reads in custom colormaps from a provided file or directory `cmap_path`; transforms them into :obj:`~matplotlib.colors.ListedColormap` objects; and makes them available in the :mod:`cmasher.cm` module, in addition to registering them in the :mod:`matplotlib.cm` module. Both the imported colormap and its reversed version will be registered. Parameters ---------- cmap_path : str Relative or absolute path to a custom colormap file; or directory that contains custom colormap files. A colormap file can be a *NumPy* binary file ('.npy'); a *viscm* source file ('.jscm'); or any text file. If the file is not a JSCM-file, it must contain the normalized RGB values that define the colormap. Notes ----- All colormap files must have names starting with the 'cm\\_' prefix. The resulting colormaps will have the name of their file without the prefix and extension. In *MPL*, the colormaps will have the added 'cmr.' prefix to avoid name clashes. Example ------- Importing a colormap named 'test' can be done by saving its normalized RGB values in a file called 'cm_test.txt' and executing >>> import_cmaps('/path/to/dir/cm_test.txt') The 'test' colormap is now available in *CMasher* and *MPL* using >>> cmr.cm.test # CMasher >>> plt.get_cmap('cmr.test') # MPL """ # Obtain path to file or directory with colormaps cmap_path = path.abspath(cmap_path) # Check if provided file or directory exists if not path.exists(cmap_path): raise OSError( "Input argument 'cmap_path' is a non-existing path (%r)!" % (cmap_path)) # Check if cmap_path is a file or directory and act accordingly if path.isfile(cmap_path): # If file, split cmap_path up into dir and file components cmap_dir, cmap_file = path.split(cmap_path) # Check if its name starts with 'cm_' and raise error if not if not cmap_file.startswith('cm_'): raise OSError("Input argument 'cmap_path' does not lead to a file " "with the 'cm_' prefix (%r)!" % (cmap_path)) # Set cm_files to be the sole read-in file cm_files = [cmap_file] else: # If directory, obtain the names of all files in cmap_path cmap_dir = cmap_path filenames = next(os.walk(cmap_dir))[2] # Extract the files with defined colormaps cm_files = [name for name in filenames if name.startswith('cm_')] cm_files.sort() # Read in all the defined colormaps, transform and register them for cm_file in cm_files: # Split basename and extension base_str, ext_str = path.splitext(cm_file) cm_name = base_str[3:] # Obtain absolute path to colormap data file cm_file_path = path.join(cmap_dir, cm_file) # Process colormap files try: # If file is a NumPy binary file if (ext_str == '.npy'): colorlist = np.load(cm_file_path).tolist() # If file is viscm source file elif (ext_str == '.jscm'): # Check if viscm is available try: import viscm # If that fails, raise error except ImportError: raise ImportError("The 'viscm' package is required to read" " '.jscm' files!") # If that succeeds, load RGB values from source file else: # Load colormap cmap = viscm.gui.Colormap(None, None, None) cmap.load(cm_file_path) # Create editor and obtain RGB values v = viscm.viscm_editor(uniform_space=cmap.uniform_space, cmtype=cmap.cmtype, method=cmap.method, **cmap.params) rgb, _ = v.cmap_model.get_sRGB(num=256) colorlist = rgb.tolist() # If file is anything else else: colorlist = np.genfromtxt(cm_file_path).tolist() # Transform colorlist into a Colormap cmap_mpl = LC(colorlist, 'cmr.' + cm_name, N=len(colorlist)) cmap_cmr = LC(colorlist, cm_name, N=len(colorlist)) cmap_mpl_r = cmap_mpl.reversed() cmap_cmr_r = cmap_cmr.reversed() # Test that the colormaps can be called cmap_mpl(1) cmap_mpl_r(1) # Determine the cm_type of the colormap cm_type = _get_cm_type(cmap_mpl) # Add cmap to matplotlib's cmap list mplcm.register_cmap(cmap=cmap_mpl) setattr(cmrcm, cmap_cmr.name, cmap_cmr) cmrcm.__all__.append(cmap_cmr.name) cmrcm.cmap_d[cmap_cmr.name] = cmap_cmr cmrcm.cmap_cd[cm_type][cmap_cmr.name] = cmap_cmr # Add reversed cmap to matplotlib's cmap list mplcm.register_cmap(cmap=cmap_mpl_r) setattr(cmrcm, cmap_cmr_r.name, cmap_cmr_r) cmrcm.__all__.append(cmap_cmr_r.name) cmrcm.cmap_d[cmap_cmr_r.name] = cmap_cmr_r cmrcm.cmap_cd[cm_type][cmap_cmr_r.name] = cmap_cmr_r # If any error is raised, reraise it except Exception as error: raise ValueError("Provided colormap %r is invalid! (%s)" % (cm_name, error))
jscm_path = path.abspath(sys.argv[1]) name = path.splitext(path.basename(jscm_path))[0] # Make a directory for the colormap files os.mkdir(name) # Move the .jscm-file to it shutil.move(jscm_path, name) # Load colormap from .jscm-file cmap = viscm.gui.Colormap(None, None, None) cmap.load("{0}/{0}.jscm".format(name)) # Obtain RGB values of colormap v = viscm.viscm_editor(uniform_space=cmap.uniform_space, cmtype=cmap.cmtype, method=cmap.method, **cmap.params) rgb, _ = v.cmap_model.get_sRGB(num=256) cmtype = cmap.cmtype elif (len(sys.argv) == 3): # Else, a diverging colormap is provided jscm_paths = [path.abspath(arg) for arg in sys.argv[1:]] name = path.basename(path.commonprefix(jscm_paths))[:-1] # Make a directory for the colormap files os.mkdir(name) # Move the .jscm-files to it for jscm_path in jscm_paths: shutil.move(jscm_path, name)
def import_cmaps(cmap_path): """ Reads in custom colormaps from a provided file or directory `cmap_path`; transforms them into :obj:`~matplotlib.colors.ListedColormap` objects; and makes them available in the :mod:`cmasher.cm` module, in addition to registering them in the :mod:`matplotlib.cm` module. Both the imported colormap and its reversed version will be registered. If a provided colormap is a 'cyclic' colormap, its shifted version will also be registered. Parameters ---------- cmap_path : str Relative or absolute path to a custom colormap file; or directory that contains custom colormap files. A colormap file can be a *NumPy* binary file ('.npy'); a *viscm* source file ('.jscm'); or any text file. If the file is not a JSCM-file, it must contain the normalized; 8-bit; or hexadecimal string RGB values that define the colormap. Notes ----- All colormap files must have names starting with the 'cm\\_' prefix. The resulting colormaps will have the name of their file without the prefix and extension. In *MPL*, the colormaps will have the added 'cmr.' prefix to avoid name clashes. Example ------- Importing a colormap named 'test' can be done by saving its normalized RGB values in a file called 'cm_test.txt' and executing >>> import_cmaps('/path/to/dir/cm_test.txt') The 'test' colormap is now available in *CMasher* and *MPL* using >>> cmr.cm.test # CMasher >>> plt.get_cmap('cmr.test') # MPL """ # Obtain path to file or directory with colormaps cmap_path = path.abspath(cmap_path) # Check if provided file or directory exists if not path.exists(cmap_path): raise OSError( "Input argument 'cmap_path' is a non-existing path (%r)!" % (cmap_path)) # Check if cmap_path is a file or directory and act accordingly if path.isfile(cmap_path): # If file, split cmap_path up into dir and file components cmap_dir, cmap_file = path.split(cmap_path) # Check if its name starts with 'cm_' and raise error if not if not cmap_file.startswith('cm_'): raise OSError("Input argument 'cmap_path' does not lead to a file " "with the 'cm_' prefix (%r)!" % (cmap_path)) # Set cm_files to be the sole read-in file cm_files = [cmap_file] else: # If directory, obtain the names of all colormap files in cmap_path cmap_dir = cmap_path cm_files = list(map(path.basename, glob("%s/cm_*" % (cmap_dir)))) cm_files.sort() # Read in all the defined colormaps, transform and register them for cm_file in cm_files: # Split basename and extension base_str, ext_str = path.splitext(cm_file) cm_name = base_str[3:] # Obtain absolute path to colormap data file cm_file_path = path.join(cmap_dir, cm_file) # Process colormap files try: # If file is a NumPy binary file if (ext_str == '.npy'): rgb = np.load(cm_file_path) # If file is viscm source file elif (ext_str == '.jscm'): # Check if viscm is available try: import viscm # If that fails, raise error except ImportError: # pragma: no cover raise ImportError("The 'viscm' package is required to read" " '.jscm' files!") # If that succeeds, load RGB values from source file else: # Load colormap cmap = viscm.gui.Colormap(None, None, None) cmap.load(cm_file_path) # Create editor and obtain RGB values v = viscm.viscm_editor(uniform_space=cmap.uniform_space, cmtype=cmap.cmtype, method=cmap.method, **cmap.params) rgb, _ = v.cmap_model.get_sRGB() # If file is anything else else: rgb = np.genfromtxt(cm_file_path, dtype=None, comments='//', encoding=None) # Register colormap register_cmap(cm_name, rgb) # Check if provided cmap is a cyclic colormap # If so, obtain its shifted (reversed) versions as well if (get_cmap_type('cmr.' + cm_name) == 'cyclic'): # Determine the central value index of the colormap idx = len(rgb) // 2 # Shift the entire colormap by this index rgb_s = np.concatenate([rgb[idx:], rgb[:idx]], axis=0) # Register this colormap as well register_cmap(cm_name + '_shifted', rgb_s) # If any error is raised, reraise it except Exception as error: raise ValueError("Provided colormap %r is invalid! (%s)" % (cm_name, error))
# Get colormap name name = path.splitext(path.basename(jscm_path))[0] # Make a directory for the colormap files os.mkdir(name) # Move the .jscm-file to it shutil.move(jscm_path, name) # Load colormap from .jscm-file cmap = viscm.gui.Colormap(None, None, None) cmap.load("{0}/{0}.jscm".format(name)) # Obtain RGB values of colormap v = viscm.viscm_editor(uniform_space=cmap.uniform_space, cmtype=cmap.cmtype, method=cmap.method, **cmap.params) rgb, _ = v.cmap_model.get_sRGB() cmtype = cmap.cmtype # Convert RGB values to string array_str = np.array2string(rgb, max_line_width=79, prefix='cm_data = ', separator=', ', threshold=rgb.size, precision=8) # Remove all whitespaces before commas for i in range(8, 0, -1): array_str = array_str.replace(' ' * i + ', ', '0' * i + ', ')