******************************************************************************** * Description of the Program - * * This program is used to download/install additional color references. The * * program either builds/installs additional colors into Stata, or will build * * lookup tables used to transform the RGB colorspace to colors that represent * * how the graph would be viewed by someone with one of the three types of * * colorblindness. This can be helpful for proofing graphs prior to publishing * * as a quality assurance/quality control method to ensure the graph can be * * viewed and interpretted correctly by the widest audience possible. * * * * Data Requirements - * * none * * * * System Requirements - * * Gunzip * * * * Program Output - * * * * Lines - * * 785 * * * ******************************************************************************** *! brewcolors *! v 1.0.0 *! 21MAR2016 // Drop the program from memory if loaded cap prog drop brewcolors // Define new program prog def brewcolors, rclass // Version number specification version 13.1 // Syntax for program (make adds to color DB, install install's colors) syntax anything(name = source) [, MAke INSTall COLors(string asis) /// REPlace OVERride ] // Check for brewscheme Mata library qui: brewlibcheck // Check for any optional arguments to add a comma to the command string if `"`make'`install'`colors'"' == "" loc optstring "," // Build local macro with the command string loc cmdstring brewcolors `source'`optstring' `make' `install' /// colors(`colors') `replace' `override' // Preserve current state of the data preserve // Clear any data from memory clear // Check for/build directory dirfile, p(`"`c(sysdir_personal)'style"') // Check for/build directory dirfile, p(`"`c(sysdir_personal)'brewcolors"') // Make sure source is valid if `"`source'"' == "xkcd" { // Load and parse the xkcd data xkcd, `make' `install' colors(`colors') `replace' cmd(`cmdstring') `override' // Loop over each of the return name macros foreach nm in `r(colnms)' { // Return the individual color name/RGB ret loc `nm' `r(`nm')' } // End Loop over returned values } // End else block for invalid source argument // If colorblind argument is passed else if `"`source'"' == "new" { // Call color blind routine colorinstaller, `make' `install' colors(`colors') `replace' cmd(`cmdstring') `override' // Return the sub routine's return value ret loc colorpath `r(colorpath)' } // End ELSE IF Block for the argument new passed to the program // Restore data to original state restore // End program end // Drop program if previously loaded in memory cap prog drop colorinstaller // Sub routine for user defined named colors prog def colorinstaller, rclass // Syntax for sub routine syntax, colors(string asis) [ make install cmd(passthru) replace override ] // Set the number of observations qui: set obs `: word count `colors'' // Create palette and RGB string variables qui: g palette = "" qui: g str11 rgb = "" // Loop over arguments passed in the color string forv i = 1/`: word count `colors'' { // Get the word string loc wrd `: word `i' of `colors'' // Tokenizes the color string argument gettoken palname rgb : wrd // If 4 total tokens assume the rgb token contains the rgb color string if `: word count `rgb'' == 3 loc colorstring `rgb' // If only 3 tokens in total, assume no name and construct palette name/ // color string macros else if `: word count `rgb'' == 2 { loc colorstring `palname' `: word 1 of `rgb'' `: word 2 of `rgb'' loc palname udc`palname'_`: word 1 of `rgb''_`: word 2 of `rgb'' } // End ELSEIF Block for no user specified name // Create a meta string loc metastring "User Defined Color - " // Generate the palette name qui: replace palette = "`palname'"' // Generate the rgb value qui: replace rgb = "`colorstring'" // Generate the rest of the variables brewcolorvars, meta(`"`metastring'"' + palette) colorb `cmd' } // End Loop over color arguments // Check install option if `"`install'"' != "" { // Loop over records forv i = 1/`: word count `colors'' { // Store filename in local macro loc fname `"`c(sysdir_personal)'style/color-`palname'.style"' // Create new file wit the color definition qui: file open newcolor using `"`fname'"', w replace // Write a version number qui: file write newcolor `"*! v 0.0.0 `c(current_date)' `c(current_time)'"' _n // Write color attribution qui: file write newcolor `"*! Color defined by the user: `c(username)'"' _n // Add a sequence ID to the file qui: file write newcolor `"sequence `: di seqid[`i']'"' _n // Write the color name qui: file write newcolor `"label "`: di meta[`i']'""' _n(2) // Write the color definition to the file qui: file write newcolor `"set rgb "`: di rgb[`i']'""' _n(2) // Close the file qui: file close newcolor } // End Loop over records } // End IF Block for color installation // Check for make option if `"`make'"' != "" { // Save the dataset with the colors qui: save `"`c(sysdir_personal)'brewcolors/colorsBy`c(username)'.dta"', replace brewColorMaker `c(sysdir_personal)'brewcolors/colorsBy`c(username)'.dta, `replace' `override' // Return the file path for the colors created by the user ret loc colorpath `"`c(sysdir_personal)'brewcolors/colorsBy`c(username)'.dta"' } // End IF Block to make the color file // End of subroutine definition end // Drop program if previously loaded in memory cap prog drop xkcd // Define sub-routine to get xkcd named color list prog def xkcd, rclass // Define syntax syntax [, make install colors(string asis) replace cmd(passthru) override ] // For the xkcd colors import delimited using "http://xkcd.com/color/rgb.txt", delim("#") clear // Get the licensing attribution loc license "`: di v2[1]'" // Drop first record with licensing data qui: drop in 1 // Make sure all letters are lowercased qui: replace v2 = lower(v2) // Remove unnecessary words from color/palette names qui: replace v1 = subinstr(v1, `"'"', "", .) qui: replace v1 = subinstr(v1, "and ", "", .) qui: replace v1 = subinstr(v1, "/", "", .) // Sort Colors alphabetically qui: sort v1 // Add XKCD Ref to meta qui: replace v1 = "XKCD - " + proper(v1) // Replace spaces in color names with underscores qui: g palette = _n qui: tostring palette, replace qui: replace palette = "xkcd" + palette // Get length of palette name string qui: g x = length(v1) // Drop the random character at the end of the color name that won't disappear otherwise qui: replace v1 = substr(v1, 1, x - 1) // Convert colors from Hexadecimal to decimal RGB values hextorgb, hex(v2) // Compress data qui: compress // Drop variables that are no longer used qui: drop v2 x // Null local macro to return all color names loc retnames // Generate sequence ID number qui: g tmpid = 6999 + _n // Loop over observations forv i = 1/949 { // Check installation option if "`install'" != "" { // Store color name loc thecolorname `: di palette[`i']' // Check to see if it is a color the user wants to install or all if (`: list thecolorname in colors' == 1 | "`install'" != "" | /// `"`colors'"' == "all") { // Build local macros to return to the user ret loc `thecolorname' `"`: di rgb[`i']'"' // Update return names loc retnames `retnames' `thecolorname' // Store filename in local macro loc fname `"`c(sysdir_personal)'style/color-`thecolorname'.style"' // Create new file wit the color definition qui: file open newcolor using `"`fname'"', w replace // Write the license info into the first line qui: file write newcolor `"*! `: subinstr loc license `"#"' "", all'"' _n // Write a version number qui: file write newcolor `"*! v 0.0.0 `c(current_date)' `c(current_time)'"' _n // Write color attribution qui: file write newcolor `"*! Color names from XKCD.com survey (http://blog.xkcd.com/2010/05/03/color-survey-results/)"' _n // Add a sequence ID to the file qui: file write newcolor `"sequence `: di tmpid[`i']'"' _n // Write the color name qui: file write newcolor `"label "`: di v1[`i']'""' _n(2) // Write the color definition to the file qui: file write newcolor `"set rgb "`: di rgb[`i']'""' _n(2) // Close the file qui: file close newcolor } // End IF Block for installable colors // If not installed skip to next iteration else continue } // End IF Block to install xkcd colors } // End Loop to return values // Return the local with the return names ret loc colnms `retnames' // Create required variables qui: brewcolorvars, meta(v1) colorb `cmd' seqid(palette + strofreal(tmpid)) // Drop variables that are no longer needed qui: drop v1 tmpid // Save the dataset qui: save `"`c(sysdir_personal)'brewcolors/brewxkcd.dta"', replace // Check make option if `"`make'"' != "" brewColorMaker `c(sysdir_personal)'brewcolors/brewxkcd.dta, `replace' `override' // End of program end // Drop program if previously loaded in memory cap prog drop brewcolorvars // Defines subroutine for adding standard variables for color definitions prog def brewcolorvars // Define syntax structure syntax [, seqid(string asis) meta(string asis) COLORBlindvars cmd(string asis) ] // Check for palette name and RGB string variables cap confirm v rgb palette // If these variables do not exist throw an error and exit if _rc != 0 { // Print error message for user di as err "The brewcolorvars subroutine called by `cmd' requires " /// "the variables palette (color/palette name) and rgb (the Stata " /// "formatted RGB string) to be present in the dataset currently in " /// "memory." // Error code err 198 } // End IF Block for bad data // Check for colorblindvars parameter if `"`colorblindvars'"' != "" { // Set the macro with the names of the color blind variables for sorting loc colorblindvars achromatopsia protanopia deuteranopia tritanopia // Generate color blindness variables qui: brewtransform rgb } // End IF Block for color blindness variables // Add variables to existing file foreach v in colorblind lcd photocopy print { // Check if variable already exists cap confirm v `v' // Initialize variables w/extended missing values if _rc != 0 qui: g `v' = .n else qui: replace `v' = .n } // End Loop for meta variables // Add id variables foreach v in pcolor colorid maxcolors { // Add variables used for IDs qui: g `v' = 1 } // End Loop over ID variables // Check for sequence ID argument if `"`seqid'"' != "" { // Create a sequence ID variable qui: g seqid = `seqid' } // End IF Block for user specified sequence id // If no argument passed else { // Generic sequence ID qui: g seqid = palette + strofreal(pcolor) + strofreal(colorid) } // End ELSE Block for no sequence ID argument // Check if meta is a variable or string cap confirm v `meta' // If argument is a variable generate the meta variable from the variable passed qui: g meta = `meta' // Specify the display order of the variables order palette colorblind print photocopy lcd colorid pcolor rgb /// maxcolors seqid meta `colorblindvars' // Variable labels la var palette "Name of Color Palette" la var colorblind "Colorblind Indicator" la var print "Print Indicator" la var photocopy "Photocopy Indicator" la var lcd "LCD/Laptop Indicator" la var colorid "Within pcolor ID for individual color look ups" la var pcolor "Palette by Colors Selected ID" la var rgb "Red-Green-Blue Values to Build Scheme Files" la var maxcolors "Maximum number of colors allowed for the palette" la var seqid "Sequential ID for property lookups" la var meta "Meta-Data Palette Characteristics (see char _meta[*] for more info)" la var achromatopsia "Achromatopsic Vision RGB Transformed Equivalent" la var protanopia "Protanopic Vision RGB Transformed Equivalent" la var deuteranopia "Deuteranopic Vision RGB Transformed Equivalent" la var tritanopia "Tritanopic Vision RGB Transformed Equivalent" // End of subroutine definition end // Drop program if previously loaded in memory cap prog drop brewColorMaker // Define program prog def brewColorMaker // Syntax syntax anything(name = filename id = "Colors to install") [, replace override ] // Append to existing colordb if it exists cap confirm new file `"`c(sysdir_personal)'brewcolors/colordb.dta"' // If file does not exist if _rc == 0 | `"`replace'"' != "" { // Call the color database program brewcolordb, `replace' `override' // Load colordb file qui: use `"`c(sysdir_personal)'brewcolors/colordb.dta"', clear // Append existing data qui: append using `"`filename'"' // Drop any duplicate color references qui: duplicates drop // Save data as first instance of colordb qui: save `"`c(sysdir_personal)'brewcolors/colordb.dta"', replace } // End ELSE Block for non-existent color database // If file exists else { // Append existing data qui: append using `"`c(sysdir_personal)'brewcolors/colordb.dta"' // Drop any duplicate color references qui: duplicates drop // Save over file qui: save `"`c(sysdir_personal)'brewcolors/colordb.dta"', replace } // End IF Block for existing color database // End of program definition end