def nth_power_scale(dataarray, nth_power): """ set nth_power to appropriate number between 0 and 1 for dampening the difference between the smallest and the largest values. If nth_power < 0 then an automatic value is computed that maps the smallest values to 0.1 of the largest values """ absdat = flex.abs(dataarray).as_double() absdat2 = graphics_utils.NoNansArray(absdat) # much faster than flex.double([e for e in absdat if not math.isnan(e)]) maxdat = flex.max(absdat2) mindat = max(1e-10*maxdat, flex.min(absdat2) ) # only autoscale for sensible values of maxdat and mindat if nth_power < 0.0 and maxdat > mindat : # amounts to automatic scale nth_power = math.log(0.2)/(math.log(mindat) - math.log(maxdat)) datascaled = flex.pow(absdat, nth_power) return datascaled, nth_power
def nth_power_scale(dataarray, nth_power): """ set nth_power to a number for dampening or enhancing the difference between the smallest and the largest values. A negative number means that a large data value is rendered with a smaller radius than a small data value. For nth_power=0 all data values are rendered with the same radius For nth_power=1 data values are rendered with radii proportional to the data values. If nth_power=NaN then an automatic value is computed that maps the smallest values to 0.1 of the largest values """ absdat = flex.abs(dataarray).as_double() absdat2 = graphics_utils.NoNansArray( absdat ) # much faster than flex.double([e for e in absdat if not math.isnan(e)]) maxdat = flex.max(absdat2) mindat = max(1e-10 * maxdat, flex.min(absdat2)) # only autoscale for sensible values of maxdat and mindat if math.isnan(nth_power) and maxdat > mindat: # amounts to automatic scale nth_power = math.log(0.2) / (math.log(mindat) - math.log(maxdat)) datascaled = flex.pow(absdat, nth_power) return datascaled, nth_power
def generate_view_data(self): from scitbx.array_family import flex #from scitbx import graphics_utils settings = self.settings data_for_colors = data_for_radii = None if not self.fullprocessarray: return data = self.data #self.work_array.data() sigmas = self.sigmas if (isinstance(data, flex.double) and data.all_eq(0)): data = flex.double(data.size(), 1) if ((self.multiplicities is not None) and (settings.scale_colors_multiplicity)): data_for_colors = self.multiplicities.data().as_double() assert data_for_colors.size() == data.size() elif (settings.sqrt_scale_colors) and (isinstance(data, flex.double)): data_for_colors = flex.sqrt(flex.abs(data)) elif isinstance(data, flex.complex_double): data_for_colors = self.radians foms_for_colours = self.foms # assuming last part of the labels indicates the phase label as in ["FCALC","PHICALC"] self.colourlabel = self.miller_array.info().labels[-1] elif (settings.sigma_color) and sigmas is not None: data_for_colors = sigmas.as_double() self.colourlabel = self.miller_array.info().labels[-1] else: data_for_colors = flex.abs(data.deep_copy()) uc = self.work_array.unit_cell() self.min_dist = min(uc.reciprocal_space_vector( (1, 1, 1))) * self.renderscale min_radius = 0.05 * self.min_dist max_radius = 0.5 * self.min_dist if ((self.multiplicities is not None) and (settings.scale_radii_multiplicity)): data_for_radii = self.multiplicities.data().as_double() if (settings.sigma_radius) and sigmas is not None: data_for_radii = sigmas * self.multiplicities.as_double() assert data_for_radii.size() == data.size() elif (settings.sigma_radius) and sigmas is not None: data_for_radii = sigmas.as_double() else: data_for_radii, self.nth_power_scale_radii = nth_power_scale( flex.abs(data.deep_copy()), settings.nth_power_scale_radii) if (settings.slice_mode): data = data.select(self.slice_selection) if (not settings.keep_constant_scale): data_for_radii = data_for_radii.select(self.slice_selection) data_for_colors = data_for_colors.select(self.slice_selection) foms_for_colours = foms_for_colours.select( self.slice_selection) if isinstance(data, flex.complex_double): if self.isUsingFOMs(): colors = graphics_utils.colour_by_phi_FOM( data_for_colors, foms_for_colours) else: colors = graphics_utils.colour_by_phi_FOM( data_for_colors, None) elif (settings.color_scheme in ["rainbow", "heatmap", "redblue"]): colors = graphics_utils.color_by_property( properties=data_for_colors, selection=flex.bool(data_for_colors.size(), True), color_all=False, gradient_type=settings.color_scheme) elif (settings.color_scheme == "grayscale"): colors = graphics_utils.grayscale_by_property( properties=data_for_colors, selection=flex.bool(data_for_colors.size(), True), shade_all=False, invert=settings.black_background) else: if (settings.black_background): base_color = (1.0, 1.0, 1.0) else: base_color = (0.0, 0.0, 0.0) colors = flex.vec3_double(data_for_colors.size(), base_color) if (settings.slice_mode) and (settings.keep_constant_scale): colors = colors.select(self.slice_selection) data_for_radii = data_for_radii.select(self.slice_selection) #if (settings.sqrt_scale_radii) and (not settings.scale_radii_multiplicity): # data_for_radii = flex.sqrt(flex.abs(data_for_radii)) if len(data_for_radii): #dat2 = flex.abs(flex.double([e for e in data_for_radii if not math.isnan(e)])) dat2 = flex.abs( flex.double(graphics_utils.NoNansArray(data_for_radii, 0.1))) # don't divide by 0 if dealing with selection of Rfree array where all values happen to be zero scale = max_radius / (flex.max(dat2) + 0.001) radii = data_for_radii * (self.settings.scale * scale) assert radii.size() == colors.size() else: radii = flex.double() max_radius = 0 self.radii = radii self.max_radius = max_radius self.min_radius = min_radius self.colors = colors if isinstance(data, flex.complex_double): self.foms = foms_for_colours
def __init__(self, millarr, wrap_labels=0): from cctbx.miller import display2 from cctbx.array_family import flex from scitbx import graphics_utils from libtbx.math_utils import roundoff import math nan = float("nan") self.wrap_labels = wrap_labels if millarr.space_group() is None: self.spginf = "?" else: self.spginf = millarr.space_group_info().symbol_and_number() if millarr.unit_cell() is None: self.ucell = (nan, nan, nan, nan, nan, nan) else: self.ucell = millarr.unit_cell().parameters() self.ucellinf = "({:.6g}Å, {:.6g}Å, {:.6g}Å, {:.6g}°, {:.6g}°, {:.6g}°)".format( *self.ucell) data = millarr.deep_copy().data() self.maxdata = self.mindata = self.maxsigmas = self.minsigmas = nan self.minmaxdata = (nan, nan) self.minmaxsigs = (nan, nan) self.data_sigdata_max = nan self.data_sigdata = nan self.desc = "" self.arrsize = data.size() if not isinstance(data, flex.std_string): if isinstance(data, flex.hendrickson_lattman): data = graphics_utils.NoNansHL(data) # estimate minmax values of HL coefficients as a simple sum if self.arrsize: self.maxdata = max( [e[0] + e[1] + e[2] + e[3] for e in data]) self.mindata = min( [e[0] + e[1] + e[2] + e[3] for e in data]) self.arrsize = len([ 42 for e in millarr.data() if not math.isnan(e[0] + e[1] + e[2] + e[3]) ]) elif isinstance(data, flex.vec3_double) or isinstance( data, flex.vec2_double): # XDS produces 2D or 3D arrays in some of its files if self.arrsize: self.maxdata = max([max(e) for e in data]) self.mindata = min([min(e) for e in data]) else: # Get a list of bools with True whenever there is a nan selection = ~graphics_utils.IsNans( flex.abs(millarr.data()).as_double()) # count elements that are not nan values self.arrsize = millarr.data().select(selection).size() if (isinstance(data, flex.int)): data = flex.double( [e for e in data if e != display2.inanval]) if millarr.is_complex_array(): data = flex.abs(data) i = 0 while math.isnan(data[i]): i += 1 # go on until we find a data[i] that isn't NaN data = graphics_utils.NoNansArray( data, data[i]) # assuming data[0] isn't NaN self.maxdata = flex.max(data) self.mindata = flex.min(data) if millarr.sigmas() is not None: data = millarr.sigmas().deep_copy() i = 0 while math.isnan(data[i]): i += 1 # go on until we find a data[i] that isn't NaN data = graphics_utils.NoNansArray(data, data[i]) self.maxsigmas = flex.max(data) self.minsigmas = flex.min(data) # Inspired by Diederichs doi:10.1107/S0907444910014836 I/SigI_asymptotic data_over_sigdata = millarr.data() / millarr.sigmas() self.data_sigdata = flex.sum(data_over_sigdata) / len( data_over_sigdata) self.data_sigdata_max = flex.max(data_over_sigdata) self.minmaxdata = (self.mindata, self.maxdata) self.minmaxsigs = (self.minsigmas, self.maxsigmas) self.labels = self.desc = self.wavelength = "" if millarr.info(): self.labels = millarr.info().labels self.desc = get_array_description(millarr) self.wavelength = "{:.6g}".format( millarr.info().wavelength) if millarr.info( ).wavelength is not None else float("nan") self.span = "(?,?,?), (?,?,?)" self.dmin = nan self.dmax = nan if millarr.unit_cell() is not None: self.span = str(millarr.index_span().min()) + ", " + str( millarr.index_span().max()) self.dmin = millarr.d_max_min()[1] self.dmax = millarr.d_max_min()[0] self.dminmax = roundoff((self.dmin, self.dmax)) self.issymunique = "?" self.isanomalous = "?" self.n_sys_abs = 0 self.n_bijvoet = self.n_singletons = 0 self.ano_mean_diff = nan self.ano_completeness = nan self.data_compl_infty = nan self.data_completeness = nan self.n_centric = nan # computations below done as in cctbx.miller.set.show_comprehensive_summary() if self.spginf != "?": self.issymunique = millarr.is_unique_set_under_symmetry() self.isanomalous = millarr.anomalous_flag() sys_absent_flags = millarr.sys_absent_flags().data() self.n_sys_abs = sys_absent_flags.count(True) if (self.n_sys_abs != 0): millarr = millarr.select(selection=~sys_absent_flags) self.n_centric = millarr.centric_flags().data().count(True) if not math.isnan(self.ucell[0]): if (self.spginf != "?" and millarr.indices().size() > 0 and self.issymunique): millarr.setup_binner(n_bins=1) completeness_d_max_d_min = millarr.completeness( use_binning=True) binner = completeness_d_max_d_min.binner assert binner.counts_given()[0] == 0 assert binner.counts_given()[2] == 0 n_obs = binner.counts_given()[1] n_complete = binner.counts_complete()[1] if (n_complete != 0 and self.dmax != self.dmin): self.data_completeness = n_obs / n_complete n_complete += binner.counts_complete()[0] if (n_complete != 0): self.data_compl_infty = n_obs / n_complete if (self.isanomalous) and (millarr.is_xray_intensity_array() or millarr.is_xray_amplitude_array()): self.ano_completeness = millarr.anomalous_completeness() if (self.spginf != "?" and self.isanomalous and self.issymunique): asu, matches = millarr.match_bijvoet_mates() self.n_bijvoet = matches.pairs().size() self.n_singletons = matches.n_singles() - self.n_centric if millarr.is_real_array(): self.ano_mean_diff = millarr.anomalous_signal() # break long label into list of shorter strings self.labelstr = ",".join(self.labels) if self.wrap_labels > 0: tlabels = textwrap.wrap(self.labelstr, width=self.wrap_labels) nlabl = len(tlabels) self.labelsformat = "{0[0]:>%d} " % (1 + self.wrap_labels) if len(tlabels) > 1: for i in range((len(tlabels) - 1)): self.labelsformat += "\n{0[%d]:>%d} " % ( i + 1, self.wrap_labels + 1) blanks = self.wrap_labels - 5 else: self.labelsformat = "{:>16} " if len(self.labelstr) > 15: self.labelsformat = "{}\n " blanks = 10 self.info_format_dict = { # the keys here must be verbatim copies of names of phil attributes in arrayinfo_phil_str below "labels": (" %s" % self.caption_dict["labels"][0] + " " * blanks, self.labelstr, "{}", self.labelsformat), "description": (" %s " % self.caption_dict["description"][0], self.desc, "{}", "{:>16} "), "wavelength": (" %s " % self.caption_dict["wavelength"][0], self.wavelength, "{}", "{:>8} "), "n_reflections": (" %s " % self.caption_dict["n_reflections"][0], self.arrsize, "{}", "{:>8} "), "span": (" " * 15 + self.caption_dict["span"][0] + " " * 14, self.span, "{}", "{:>32} "), "minmax_data": (" %s " % self.caption_dict["minmax_data"][0], self.minmaxdata, "{0[0]:.6}, {0[1]:.6}", "{0[0]:>11.5}, {0[1]:>11.5}"), "minmax_sigmas": (" %s " % self.caption_dict["minmax_sigmas"][0], self.minmaxsigs, "{0[0]:.6}, {0[1]:.6}", "{0[0]:>11.5}, {0[1]:>11.5}"), "data_sigdata": (" %s" % self.caption_dict["data_sigdata"][0], self.data_sigdata, "{:.4g}", "{:>9.4g} "), "data_sigdata_max": ("%s" % self.caption_dict["data_sigdata_max"][0], self.data_sigdata_max, "{:.4g}", "{:>11.4g} "), "d_minmax": (" %s " % self.caption_dict["d_minmax"][0], self.dminmax, "{0[0]:.6}, {0[1]:.6}", "{0[0]:>8.5}, {0[1]:>8.5}"), "unit_cell": (" %s " % self.caption_dict["unit_cell"][0], self.ucell, "{0[0]:>7.5g},{0[1]:>7.5g},{0[2]:>7.5g},{0[3]:>7.5g},{0[4]:>7.5g},{0[5]:>7.5g}", "{0[0]:>7.5g},{0[1]:>7.5g},{0[2]:>7.5g},{0[3]:>7.5g},{0[4]:>7.5g},{0[5]:>7.5g} " ), "space_group": (" %s " % self.caption_dict["space_group"][0], self.spginf, "{}", "{:>19} "), "n_centrics": ("%s" % self.caption_dict["n_centrics"][0], self.n_centric, "{}", "{:>8} "), "n_sys_abs": ("%s" % self.caption_dict["n_sys_abs"][0], self.n_sys_abs, "{}", "{:>9} "), "data_completeness": ("%s" % self.caption_dict["data_completeness"][0], self.data_completeness, "{:.5g}", "{:>10.5g} "), "data_compl_infty": ("%s" % self.caption_dict["data_compl_infty"][0], self.data_compl_infty, "{:.5g}", "{:>9.5g} "), "is_anomalous": ("%s" % self.caption_dict["is_anomalous"][0], str(self.isanomalous), "{}", "{:>8} "), "is_symmetry_unique": ("%s" % self.caption_dict["is_symmetry_unique"][0], str(self.issymunique), "{}", "{:>8} "), "ano_completeness": ("%s" % self.caption_dict["ano_completeness"][0], self.ano_completeness, "{:.5g}", "{:>11.5g} "), "ano_mean_diff": ("%s" % self.caption_dict["ano_mean_diff"][0], self.ano_mean_diff, "{:.5g}", "{:>8.5g} "), "n_bijvoet": ("%s" % self.caption_dict["n_bijvoet"][0], self.n_bijvoet, "{}", "{:>8} "), "n_singletons": ("%s" % self.caption_dict["n_singletons"][0], self.n_singletons, "{}", "{:>10} "), }
def generate_view_data(self): from scitbx.array_family import flex settings = self.settings data_for_colors = data_for_radii = None if not self.fullprocessarray: return data = self.data #self.work_array.data() sigmas = self.sigmas if (isinstance(data, flex.double) and data.all_eq(0)): data = flex.double(data.size(), 1) if isinstance(data, flex.complex_double): data_for_colors = self.phases foms_for_colours = self.foms # assuming last part of the labels indicates the phase label as in ["FCALC","PHICALC"] self.colourlabel = "Phase of " + self.miller_array.info( ).label_string() elif (settings.sigma_color_radius) and sigmas is not None: data_for_colors = sigmas.as_double() self.colourlabel = "Sigma of " + self.miller_array.info( ).label_string() else: data_for_colors = flex.abs(data.deep_copy()) uc = self.work_array.unit_cell() self.min_dist = min(uc.reciprocal_space_vector( (1, 1, 1))) * self.renderscale min_radius = 0.05 * self.min_dist max_radius = 0.5 * self.min_dist if (settings.sigma_color_radius) and sigmas is not None: data_for_radii, self.nth_power_scale_radii = nth_power_scale( flex.abs(sigmas.as_double().deep_copy()), settings.nth_power_scale_radii) else: data_for_radii, self.nth_power_scale_radii = nth_power_scale( flex.abs(data.deep_copy()), settings.nth_power_scale_radii) if (settings.slice_mode): data = data.select(self.slice_selection) # Computing rgb colours of each reflection is slow so make a small array # of precomputed colours to use as a lookup table for each reflection if isinstance(data, flex.complex_double): COL = MplColorHelper(settings.color_scheme, 0, 360) rgbcolarray = [COL.get_rgb(d)[0:3] for d in range(360)] if self.isUsingFOMs(): colors = graphics_utils.map_to_rgb_colourmap( data_for_colors=data_for_colors, colormap=rgbcolarray, selection=flex.bool(data_for_colors.size(), True), attenuation=foms_for_colours, map_directly=True, color_all=False) else: colors = graphics_utils.map_to_rgb_colourmap( data_for_colors=data_for_colors, colormap=rgbcolarray, selection=flex.bool(data_for_colors.size(), True), attenuation=None, map_directly=True, color_all=False) else: # Use a colour gradient from matplotlib COL = MplColorHelper(settings.color_scheme, 0, 199) colorgradientarray = flex.vec3_double( [COL.get_rgb(d)[0:3] for d in range(200)]) # Do the table lookup in C++ for speed improvement colors = graphics_utils.map_to_rgb_colourmap( data_for_colors=data_for_colors, colormap=colorgradientarray, selection=flex.bool(data_for_colors.size(), True), powscale=settings.color_powscale, attenuation=None, color_all=False) if (settings.slice_mode): colors = colors.select(self.slice_selection) data_for_radii = data_for_radii.select(self.slice_selection) if len(data_for_radii): #dat2 = flex.abs(flex.double([e for e in data_for_radii if not math.isnan(e)])) dat2 = flex.abs( flex.double(graphics_utils.NoNansArray(data_for_radii, 0.1))) # don't divide by 0 if dealing with selection of Rfree array where all values happen to be zero scale = max_radius / (flex.max(dat2) + 0.001) radii = data_for_radii * (self.settings.scale * scale) assert radii.size() == colors.size() else: radii = flex.double() max_radius = 0 self.radii = radii self.max_radius = max_radius self.min_radius = min_radius self.colors = colors if isinstance(data, flex.complex_double): self.foms = foms_for_colours