595ae73a63776a07d8d47fad24b2f3a4cf23f040 max Mon Jul 21 13:26:47 2025 -0700 allowing 8-digit hex color codes, mouse-dev-cardiac-spatial, marc diff --git src/cbPyLib/cellbrowser/cellbrowser.py src/cbPyLib/cellbrowser/cellbrowser.py index 4d5493b..bafab71 100755 --- src/cbPyLib/cellbrowser/cellbrowser.py +++ src/cbPyLib/cellbrowser/cellbrowser.py @@ -2050,30 +2050,31 @@ else: logging.debug("%s is not an MTX file" % path) return False def exprEncode(geneDesc, exprArr, matType): """ convert an array of numbers of type matType (int or float) to a compressed string of float32s The format of a record is: - 2 bytes: length of descStr, e.g. gene identifier or else - len(descStr) bytes: the descriptive string descStr - array of n 4-byte floats (n = number of cells) or 4-byte unsigned ints """ geneDesc = str(geneDesc) # make sure no unicode geneIdLen = struct.pack("<H", len(geneDesc)) + nanValue = None if matType=="float": nanValue = FLOATNAN else: nanValue = INTNAN # on cortex-dev, numpy was around 30% faster. Not a huge difference. if numpyLoaded: if matType=="float": exprArr = exprArr.astype("float32") elif matType=="int": exprArr = exprArr.astype("uint32") else: assert(False) # internal error exprStr = exprArr.tobytes() exprArr[np.isnan(exprArr)] = nanValue @@ -2249,31 +2250,36 @@ else: if atacChromCount > 100: errAbort("There are more than 100 genes that look like a chrom_start_end range but the atacSearch cellbrowser.conf" " is not set. Please add this option or contact us if you are confused about this error.") if highCount==0: logging.warn("No single value in the matrix is > 100. It looks like this " "matrix has been log'ed. Our recommendation for visual inspection is to not transform matrices") if len(exprIndex)==0: errAbort("No genes from the expression matrix could be mapped to symbols." "Are you sure these are Ensembl IDs? Adapt geneIdType in cellbrowser.conf.") # keep a flag so the client later can figure out if the expression matrix contains any negative values # this is important for handling the 0-value - exprIndex["_range"] = (float(allMin),0) # float() in case it is -inf as a np.float32, must be native Python float, not numpy + matrixMin = float(allMin) # float() in case it is -inf as a np.float32, must be native Python float, not numpy + if matrixMin==float('-inf'): # JSON cannot encode -inf nor NaN, so we use "None" for that which will become null in JSON + matrixMin = None + + exprIndex["_range"] = (matrixMin, 0) + logging.info("Global minimum in matrix is: %f" % allMin) jsonOfh = open(jsonFname, "w") json.dump(exprIndex, jsonOfh) jsonOfh.close() jsonOfh = open(discretJsonFname, "w") json.dump(discretIndex, jsonOfh) jsonOfh.close() renameFile(tmpFname, binFname) renameFile(discretTmp, discretBinFname) return matType @@ -2342,31 +2348,39 @@ if len(row)!=2: errAbort("color file %s - line %d does not contain exactly two fields: %s" % (fname, lineNo, row)) metaVal, color = row if metaVal.lower().startswith("color") or metaVal.lower().startswith("colour"): # tolerate a header line, otherwise will stop with "color not found" invColumns = True continue if color.lower().startswith("color") or color.lower().startswith("colour"): # tolerate a header line, otherwise will stop with "color not found" continue if invColumns: color, metaVal = row - color = color.strip().strip("#") # hbeale had a file with trailing spaces + color = color.strip() # hbeale had a 6-digit file with trailing spaces + + if color.startswith("#") and len(color)==9: + # we got these a few times now: #abababff + logging.warn("Color %s looks like a hex color with alpha value, stripping last two characters" + % color) + color = color[1:7] + + color = color.strip("#") # hbeale had a 6-digit file with trailing spaces isHex = True if len(color)!=6: # colors can be no more than six hex digits isHex = False else: for c in color: if (c not in "0123456789ABCDEFabcdef"): isHex = False break if not isHex: logging.debug("Not a six-digit hex color code. Trying to map '%s' to a hex color" % color) import webcolors # error? -> pip install webcolors try: color = webcolors.name_to_hex(color, spec='css3').lstrip("#")