def test_htmlify(self): self.assertEqual( htmlify("Li3Fe2(PO4)3"), "Li<sub>3</sub>Fe<sub>2</sub>(PO<sub>4</sub>)<sub>3</sub>", ) self.assertEqual(htmlify("Li0.2Na0.8Cl"), "Li<sub>0.2</sub>Na<sub>0.8</sub>Cl")
def _get_xaxis_title(self, latex: bool = True) -> str: """Returns the formatted title of the x axis (using either html/latex)""" if latex: f1 = latexify(self.c1.reduced_formula) f2 = latexify(self.c2.reduced_formula) title = f"$x$ in $x${f1} + $(1-x)${f2}" else: f1 = htmlify(self.c1.reduced_formula) f2 = htmlify(self.c2.reduced_formula) title = f"<i>x</i> in <i>x</i>{f1} + (1-<i>x</i>){f2}" return title
def _get_annotation(ann_loc: np.ndarray, formula: str) -> Dict[str, Union[str, float]]: """Returns a Plotly annotation dict given a formula and location""" formula = htmlify(formula) annotation = plotly_layouts["default_annotation_layout"].copy() annotation.update({"x": ann_loc[0], "y": ann_loc[1], "text": formula}) if len(ann_loc) == 3: annotation.update({"z": ann_loc[2]}) return annotation
def _get_plotly_annotations(x: List[float], y: List[float], reactions: List[Reaction]): """Returns dictionary of annotations for the Plotly figure layout""" annotations = [] for x_coord, y_coord, rxn in zip(x, y, reactions): products = ", ".join( [htmlify(p.reduced_formula) for p in rxn.products if not np.isclose(rxn.get_coeff(p), 0)] ) annotation = dict(x=x_coord, y=y_coord, text=products, font=dict(size=18), ax=-25, ay=55) annotations.append(annotation) return annotations
def get_all_component_descriptions(self) -> str: """Gets the descriptions of all components in the structure. Returns: A description of all components in the structure. """ if len(self._da.components) == 1: return self.get_component_description( self._da.get_component_groups()[0].components[0].index, single_component=True, ) else: component_groups = self._da.get_component_groups() component_descriptions = [] for group in component_groups: for component in group.components: if group.molecule_name: # don't describe known molecules continue formula = group.formula group_count = group.count component_count = component.count shape = dimensionality_to_shape[group.dimensionality] if self.fmt == "latex": formula = latexify(formula) elif self.fmt == "unicode": formula = unicodeify(formula) elif self.fmt == "html": formula = htmlify(formula) if group_count == component_count: s_filler = "the" if group_count == 1 else "each" else: s_filler = "{} of the".format( en.number_to_words(component_count) ) shape = en.plural(shape) desc = f"In {s_filler} {formula} {shape}, " desc += self.get_component_description(component.index) component_descriptions.append(desc) return " ".join(component_descriptions)
def get_mineral_description(self) -> str: """Gets the mineral name and space group description. If the structure is a perfect match for a known prototype (e.g. the distance parameter is -1, the mineral name is the prototype name. If a structure is not a perfect match but similar to a known mineral, "-like" will be added to the mineral name. If the structure is a good match to a mineral but contains a different number of element types than the mineral prototype, "-derived" will be added to the mineral name. Returns: The description of the mineral name. """ spg_symbol = self._da.spg_symbol formula = self._da.formula if self.fmt == "latex": spg_symbol = latexify_spacegroup(self._da.spg_symbol) formula = latexify(formula) elif self.fmt == "unicode": spg_symbol = unicodeify_spacegroup(self._da.spg_symbol) formula = unicodeify(formula) elif self.fmt == "html": spg_symbol = htmlify_spacegroup(self._da.spg_symbol) formula = htmlify(formula) mineral_name = get_mineral_name(self._da.mineral) if mineral_name: desc = f"{formula} is {mineral_name} structured and" else: desc = f"{formula}" desc += " crystallizes in the {} {} space group.".format( self._da.crystal_system, spg_symbol ) return desc
def _get_poly_site_description(self, site_index: int): """Gets a description of a connected polyhedral site. If the site likeness (order parameter) is less than ``distorted_tol``, "distorted" will be added to the geometry description. Args: site_index: An inequivalent site index. Returns: A description the a polyhedral site, including connectivity. """ site = self._da.sites[site_index] nnn_details = self._da.get_next_nearest_neighbor_details( site_index, group=not self.describe_symmetry_labels ) from_element = get_formatted_el( site["element"], self._da.sym_labels[site_index], use_oxi_state=self.describe_oxidation_state, use_sym_label=self.describe_symmetry_labels, fmt=self.fmt, ) from_poly_formula = site["poly_formula"] if self.fmt == "latex": from_poly_formula = latexify(from_poly_formula) elif self.fmt == "unicode": from_poly_formula = unicodeify(from_poly_formula) elif self.fmt == "html": from_poly_formula = htmlify(from_poly_formula) s_from_poly_formula = get_el(site["element"]) + from_poly_formula if site["geometry"]["likeness"] < self.distorted_tol: s_distorted = "distorted " else: s_distorted = "" s_polyhedra = geometry_to_polyhedra[site["geometry"]["type"]] s_polyhedra = polyhedra_plurals[s_polyhedra] nn_desc = self._get_nearest_neighbor_description(site_index) desc = f"{from_element} is bonded to {nn_desc} to form " # handle the case we were are connected to the same type of polyhedra if ( nnn_details[0].element == site["element"] and len( {(nnn_site.element, nnn_site.poly_formula) for nnn_site in nnn_details} ) ) == 1: connectivities = list({nnn_site.connectivity for nnn_site in nnn_details}) s_mixture = "a mixture of " if len(connectivities) != 1 else "" s_connectivities = en.join(connectivities) desc += "{}{}{}-sharing {} {}".format( s_mixture, s_distorted, s_connectivities, s_from_poly_formula, s_polyhedra, ) return desc # otherwise loop through nnn connectivities and describe individually desc += "{}{} {} that share ".format( s_distorted, s_from_poly_formula, s_polyhedra ) nnn_descriptions = [] for nnn_site in nnn_details: to_element = get_formatted_el( nnn_site.element, nnn_site.sym_label, use_oxi_state=False, use_sym_label=self.describe_symmetry_labels, ) to_poly_formula = nnn_site.poly_formula if self.fmt == "latex": to_poly_formula = latexify(to_poly_formula) elif self.fmt == "unicode": to_poly_formula = unicodeify(to_poly_formula) elif self.fmt == "html": to_poly_formula = htmlify(to_poly_formula) to_poly_formula = to_element + to_poly_formula to_shape = geometry_to_polyhedra[nnn_site.geometry] if len(nnn_site.sites) == 1 and nnn_site.count != 1: s_equivalent = " equivalent " else: s_equivalent = " " if nnn_site.count == 1: s_an = f" {en.an(nnn_site.connectivity)}" else: s_an = "" to_shape = polyhedra_plurals[to_shape] nnn_descriptions.append( "{}{} with {}{}{} {}".format( s_an, en.plural(nnn_site.connectivity, nnn_site.count), en.number_to_words(nnn_site.count), s_equivalent, to_poly_formula, to_shape, ) ) return desc + en.join(nnn_descriptions)
def get_component_makeup_summary(self) -> str: """Gets a summary of the makeup of components in a structure. Returns: A description of the number of components and their dimensionalities and orientations. """ component_groups = self._da.get_component_groups() if ( len(component_groups) == 1 and component_groups[0].count == 1 and component_groups[0].dimensionality == 3 ): desc = "" else: if self._da.dimensionality == 3: desc = "The structure consists of " else: desc = "The structure is {}-dimensional and consists of " "".format( en.number_to_words(self._da.dimensionality) ) component_makeup_summaries = [] nframeworks = len( [ c for g in component_groups for c in g.components if c.dimensionality == 3 ] ) for component_group in component_groups: if nframeworks == 1 and component_group.dimensionality == 3: s_count = "a" else: s_count = en.number_to_words(component_group.count) dimensionality = component_group.dimensionality if component_group.molecule_name: if component_group.nsites == 1: shape = "atom" else: shape = "molecule" shape = en.plural(shape, s_count) formula = component_group.molecule_name else: shape = en.plural(dimensionality_to_shape[dimensionality], s_count) formula = component_group.formula if self.fmt == "latex": formula = latexify(formula) elif self.fmt == "unicode": formula = unicodeify(formula) print(formula) elif self.fmt == "html": formula = htmlify(formula) comp_desc = f"{s_count} {formula} {shape}" if component_group.dimensionality in [1, 2]: orientations = list( {c.orientation for c in component_group.components} ) s_direction = en.plural("direction", len(orientations)) comp_desc += " oriented in the {} {}".format( en.join(orientations), s_direction ) component_makeup_summaries.append(comp_desc) if nframeworks == 1 and len(component_makeup_summaries) > 1: # when there is a single framework, make the description read # "... and 8 Sn atoms inside a SnO2 framework" instead of # "..., 8 Sn atoms and one SnO2 framework" # This works because the component summaries are sorted by # dimensionality desc += en.join(component_makeup_summaries[:-1]) desc += f" inside {component_makeup_summaries[-1]}." else: desc += en.join(component_makeup_summaries) + "." return desc
def test_htmlify(self): self.assertEqual(htmlify("Li3Fe2(PO4)3"), "Li<sub>3</sub>Fe<sub>2</sub>(PO<sub>4</sub>)<sub>3</sub>") self.assertEqual(htmlify("Li0.2Na0.8Cl"), "Li<sub>0.2</sub>Na<sub>0.8</sub>Cl")