def get_indexer(self, target, method=None, limit=None, tolerance=None): if com.any_not_none(method, tolerance, limit) or not is_list_like(target): return super().get_indexer(target, method=method, tolerance=tolerance, limit=limit) if self.step > 0: start, stop, step = self.start, self.stop, self.step else: # GH 28678: work on reversed range for simplicity reverse = self._range[::-1] start, stop, step = reverse.start, reverse.stop, reverse.step target_array = np.asarray(target) if not (is_integer_dtype(target_array) and target_array.ndim == 1): # checks/conversions/roundings are delegated to general method return super().get_indexer(target, method=method, tolerance=tolerance) locs = target_array - start valid = (locs % step == 0) & (locs >= 0) & (target_array < stop) locs[~valid] = -1 locs[valid] = locs[valid] / step if step != self.step: # We reversed this range: transform to original locs locs[valid] = len(self) - 1 - locs[valid] return ensure_platform_int(locs)
def _get_indexer( self, target: Index, method: str | None = None, limit: int | None = None, tolerance=None, ) -> npt.NDArray[np.intp]: if com.any_not_none(method, tolerance, limit): return super()._get_indexer( target, method=method, tolerance=tolerance, limit=limit ) if self.step > 0: start, stop, step = self.start, self.stop, self.step else: # GH 28678: work on reversed range for simplicity reverse = self._range[::-1] start, stop, step = reverse.start, reverse.stop, reverse.step target_array = np.asarray(target) locs = target_array - start valid = (locs % step == 0) & (locs >= 0) & (target_array < stop) locs[~valid] = -1 locs[valid] = locs[valid] / step if step != self.step: # We reversed this range: transform to original locs locs[valid] = len(self) - 1 - locs[valid] return ensure_platform_int(locs)
def get_consensus_names(indexes): """ Give a consensus 'names' to indexes. If there's exactly one non-empty 'names', return this, otherwise, return empty. Parameters ---------- indexes : list of Index objects Returns ------- list A list representing the consensus 'names' found. """ # find the non-none names, need to tupleify to make # the set hashable, then reverse on return consensus_names = { tuple(i.names) for i in indexes if com.any_not_none(*i.names) } if len(consensus_names) == 1: return list(list(consensus_names)[0]) return [None] * indexes[0].nlevels
def _get_indexer( self, target: Index, method: str | None = None, limit: int | None = None, tolerance=None, ) -> np.ndarray: # -> np.ndarray[np.intp] if com.any_not_none(method, tolerance, limit): return super()._get_indexer( target, method=method, tolerance=tolerance, limit=limit ) if self.step > 0: start, stop, step = self.start, self.stop, self.step else: # GH 28678: work on reversed range for simplicity reverse = self._range[::-1] start, stop, step = reverse.start, reverse.stop, reverse.step if not is_signed_integer_dtype(target): # checks/conversions/roundings are delegated to general method return super()._get_indexer(target, method=method, tolerance=tolerance) target_array = np.asarray(target) locs = target_array - start valid = (locs % step == 0) & (locs >= 0) & (target_array < stop) locs[~valid] = -1 locs[valid] = locs[valid] / step if step != self.step: # We reversed this range: transform to original locs locs[valid] = len(self) - 1 - locs[valid] return ensure_platform_int(locs)
def _get_index_name(self): if isinstance(self.data.index, ABCMultiIndex): name = self.data.index.names if com.any_not_none(*name): name = ",".join(pprint_thing(x) for x in name) else: name = None else: name = self.data.index.name if name is not None: name = pprint_thing(name) return name
def _make_plot(self): if self._is_ts_plot(): from pandas.plotting._matplotlib.timeseries import _maybe_convert_index data = _maybe_convert_index(self._get_ax(0), self.data) x = data.index # dummy, not used plotf = self._ts_plot it = self._iter_data(data=data, keep_index=True) else: x = self._get_xticks(convert_period=True) plotf = self._plot it = self._iter_data() stacking_id = self._get_stacking_id() is_errorbar = com.any_not_none(*self.errors.values()) colors = self._get_colors() for i, (label, y) in enumerate(it): ax = self._get_ax(i) kwds = self.kwds.copy() style, kwds = self._apply_style_colors(colors, kwds, i, label) errors = self._get_errorbars(label=label, index=i) kwds = dict(kwds, **errors) label = pprint_thing(label) # .encode('utf-8') kwds["label"] = label newlines = plotf( ax, x, y, style=style, column_num=i, stacking_id=stacking_id, is_errorbar=is_errorbar, **kwds, ) self._add_legend_handle(newlines[0], label, index=i) if self._is_ts_plot(): # reset of xlim should be used for ts data # TODO: GH28021, should find a way to change view limit on xaxis lines = _get_all_lines(ax) left, right = _get_xlim(lines) ax.set_xlim(left, right)
def _make_plot(self): if self._is_ts_plot(): from pandas.plotting._matplotlib.timeseries import _maybe_convert_index data = _maybe_convert_index(self._get_ax(0), self.data) x = data.index # dummy, not used plotf = self._ts_plot it = self._iter_data(data=data, keep_index=True) else: x = self._get_xticks(convert_period=True) plotf = self._plot it = self._iter_data() stacking_id = self._get_stacking_id() is_errorbar = com.any_not_none(*self.errors.values()) colors = self._get_colors() for i, (label, y) in enumerate(it): ax = self._get_ax(i) kwds = self.kwds.copy() style, kwds = self._apply_style_colors(colors, kwds, i, label) errors = self._get_errorbars(label=label, index=i) kwds = dict(kwds, **errors) label = pprint_thing(label) # .encode('utf-8') kwds["label"] = label newlines = plotf( ax, x, y, style=style, column_num=i, stacking_id=stacking_id, is_errorbar=is_errorbar, **kwds ) self._add_legend_handle(newlines[0], label, index=i) # GH27686 set_xlim will truncate xaxis to fixed space ax.relim()
def _format_hierarchical_rows(self) -> Iterable[ExcelCell]: if self._has_aliases or self.header: self.rowcounter += 1 gcolidx = 0 if self.index: index_labels = self.df.index.names # check for aliases if self.index_label and isinstance( self.index_label, (list, tuple, np.ndarray, Index)): index_labels = self.index_label # MultiIndex columns require an extra row # with index names (blank if None) for # unambiguous round-trip, unless not merging, # in which case the names all go on one row Issue #11328 if isinstance(self.columns, MultiIndex) and self.merge_cells: self.rowcounter += 1 # if index labels are not empty go ahead and dump if com.any_not_none(*index_labels) and self.header is not False: for cidx, name in enumerate(index_labels): yield ExcelCell(self.rowcounter - 1, cidx, name, self.header_style) if self.merge_cells: # Format hierarchical rows as merged cells. level_strs = self.df.index.format(sparsify=True, adjoin=False, names=False) level_lengths = get_level_lengths(level_strs) for spans, levels, level_codes in zip(level_lengths, self.df.index.levels, self.df.index.codes): values = levels.take( level_codes, allow_fill=levels._can_hold_na, fill_value=levels._na_value, ) for i, span_val in spans.items(): spans_multiple_cells = span_val > 1 yield ExcelCell( row=self.rowcounter + i, col=gcolidx, val=values[i], style=self.header_style, mergestart=(self.rowcounter + i + span_val - 1 if spans_multiple_cells else None), mergeend=gcolidx if spans_multiple_cells else None, ) gcolidx += 1 else: # Format hierarchical rows with non-merged values. for indexcolvals in zip(*self.df.index): for idx, indexcolval in enumerate(indexcolvals): yield ExcelCell( row=self.rowcounter + idx, col=gcolidx, val=indexcolval, style=self.header_style, ) gcolidx += 1 yield from self._generate_body(gcolidx)
def _translate(self): """ Convert the DataFrame in `self.data` and the attrs from `_build_styles` into a dictionary of {head, body, uuid, cellstyle}. """ table_styles = self.table_styles or [] caption = self.caption ctx = self.ctx precision = self.precision hidden_index = self.hidden_index hidden_columns = self.hidden_columns uuid = self.uuid or str(uuid1()).replace("-", "_") ROW_HEADING_CLASS = "row_heading" COL_HEADING_CLASS = "col_heading" INDEX_NAME_CLASS = "index_name" DATA_CLASS = "data" BLANK_CLASS = "blank" BLANK_VALUE = "" def format_attr(pair): return "{key}={value}".format(**pair) # for sparsifying a MultiIndex idx_lengths = _get_level_lengths(self.index) col_lengths = _get_level_lengths(self.columns, hidden_columns) cell_context = dict() n_rlvls = self.data.index.nlevels n_clvls = self.data.columns.nlevels rlabels = self.data.index.tolist() clabels = self.data.columns.tolist() if n_rlvls == 1: rlabels = [[x] for x in rlabels] if n_clvls == 1: clabels = [[x] for x in clabels] clabels = list(zip(*clabels)) cellstyle = [] head = [] for r in range(n_clvls): # Blank for Index columns... row_es = [ { "type": "th", "value": BLANK_VALUE, "display_value": BLANK_VALUE, "is_visible": not hidden_index, "class": " ".join([BLANK_CLASS]), } ] * (n_rlvls - 1) # ... except maybe the last for columns.names name = self.data.columns.names[r] cs = [ BLANK_CLASS if name is None else INDEX_NAME_CLASS, "level{lvl}".format(lvl=r), ] name = BLANK_VALUE if name is None else name row_es.append( { "type": "th", "value": name, "display_value": name, "class": " ".join(cs), "is_visible": not hidden_index, } ) if clabels: for c, value in enumerate(clabels[r]): cs = [ COL_HEADING_CLASS, "level{lvl}".format(lvl=r), "col{col}".format(col=c), ] cs.extend( cell_context.get("col_headings", {}).get(r, {}).get(c, []) ) es = { "type": "th", "value": value, "display_value": value, "class": " ".join(cs), "is_visible": _is_visible(c, r, col_lengths), } colspan = col_lengths.get((r, c), 0) if colspan > 1: es["attributes"] = [ format_attr({"key": "colspan", "value": colspan}) ] row_es.append(es) head.append(row_es) if ( self.data.index.names and com.any_not_none(*self.data.index.names) and not hidden_index ): index_header_row = [] for c, name in enumerate(self.data.index.names): cs = [INDEX_NAME_CLASS, "level{lvl}".format(lvl=c)] name = "" if name is None else name index_header_row.append( {"type": "th", "value": name, "class": " ".join(cs)} ) index_header_row.extend( [{"type": "th", "value": BLANK_VALUE, "class": " ".join([BLANK_CLASS])}] * (len(clabels[0]) - len(hidden_columns)) ) head.append(index_header_row) body = [] for r, idx in enumerate(self.data.index): row_es = [] for c, value in enumerate(rlabels[r]): rid = [ ROW_HEADING_CLASS, "level{lvl}".format(lvl=c), "row{row}".format(row=r), ] es = { "type": "th", "is_visible": (_is_visible(r, c, idx_lengths) and not hidden_index), "value": value, "display_value": value, "id": "_".join(rid[1:]), "class": " ".join(rid), } rowspan = idx_lengths.get((c, r), 0) if rowspan > 1: es["attributes"] = [ format_attr({"key": "rowspan", "value": rowspan}) ] row_es.append(es) for c, col in enumerate(self.data.columns): cs = [DATA_CLASS, "row{row}".format(row=r), "col{col}".format(col=c)] cs.extend(cell_context.get("data", {}).get(r, {}).get(c, [])) formatter = self._display_funcs[(r, c)] value = self.data.iloc[r, c] row_dict = { "type": "td", "value": value, "class": " ".join(cs), "display_value": formatter(value), "is_visible": (c not in hidden_columns), } # only add an id if the cell has a style if self.cell_ids or not (len(ctx[r, c]) == 1 and ctx[r, c][0] == ""): row_dict["id"] = "_".join(cs[1:]) row_es.append(row_dict) props = [] for x in ctx[r, c]: # have to handle empty styles like [''] if x.count(":"): props.append(x.split(":")) else: props.append(["", ""]) cellstyle.append( { "props": props, "selector": "row{row}_col{col}".format(row=r, col=c), } ) body.append(row_es) table_attr = self.table_attributes use_mathjax = get_option("display.html.use_mathjax") if not use_mathjax: table_attr = table_attr or "" if 'class="' in table_attr: table_attr = table_attr.replace('class="', 'class="tex2jax_ignore ') else: table_attr += ' class="tex2jax_ignore"' return dict( head=head, cellstyle=cellstyle, body=body, uuid=uuid, precision=precision, table_styles=table_styles, caption=caption, table_attributes=table_attr, )
def _translate_header(self, blank_class, blank_value, index_name_class, col_heading_class): """ Build each <tr> within table <head>, using the structure: +----------------------------+---------------+---------------------------+ | index_blanks ... | column_name_0 | column_headers (level_0) | 1) | .. | .. | .. | | index_blanks ... | column_name_n | column_headers (level_n) | +----------------------------+---------------+---------------------------+ 2) | index_names (level_0 to level_n) ... | column_blanks ... | +----------------------------+---------------+---------------------------+ """ # for sparsifying a MultiIndex col_lengths = _get_level_lengths(self.columns, self.hidden_columns) clabels = self.data.columns.tolist() if self.data.columns.nlevels == 1: clabels = [[x] for x in clabels] clabels = list(zip(*clabels)) head = [] # 1) column headers for r in range(self.data.columns.nlevels): index_blanks = [ _element("th", blank_class, blank_value, not self.hidden_index) ] * (self.data.index.nlevels - 1) name = self.data.columns.names[r] column_name = [ _element( "th", f"{blank_class if name is None else index_name_class} level{r}", name if name is not None else blank_value, not self.hidden_index, ) ] if clabels: column_headers = [ _element( "th", f"{col_heading_class} level{r} col{c}", value, _is_visible(c, r, col_lengths), attributes=(f'colspan="{col_lengths.get((r, c), 0)}"' if col_lengths.get((r, c), 0) > 1 else ""), ) for c, value in enumerate(clabels[r]) ] head.append(index_blanks + column_name + column_headers) # 2) index names if (self.data.index.names and com.any_not_none(*self.data.index.names) and not self.hidden_index): index_names = [ _element( "th", f"{index_name_class} level{c}", blank_value if name is None else name, True, ) for c, name in enumerate(self.data.index.names) ] column_blanks = [ _element( "th", f"{blank_class} col{c}", blank_value, c not in self.hidden_columns, ) for c in range(len(clabels[0])) ] head.append(index_names + column_blanks) return head
def _translate_header( self, blank_class: str, blank_value: str, index_name_class: str, col_heading_class: str, sparsify_cols: bool, ): """ Build each <tr> within table <head> as a list Using the structure: +----------------------------+---------------+---------------------------+ | index_blanks ... | column_name_0 | column_headers (level_0) | 1) | .. | .. | .. | | index_blanks ... | column_name_n | column_headers (level_n) | +----------------------------+---------------+---------------------------+ 2) | index_names (level_0 to level_n) ... | column_blanks ... | +----------------------------+---------------+---------------------------+ Parameters ---------- blank_class : str CSS class added to elements within blank sections of the structure. blank_value : str HTML display value given to elements within blank sections of the structure. index_name_class : str CSS class added to elements within the index_names section of the structure. col_heading_class : str CSS class added to elements within the column_names section of structure. sparsify_cols : bool Whether column_headers section will add colspan attributes (>1) to elements. Returns ------- head : list The associated HTML elements needed for template rendering. """ # for sparsifying a MultiIndex col_lengths = _get_level_lengths(self.columns, sparsify_cols, self.hidden_columns) clabels = self.data.columns.tolist() if self.data.columns.nlevels == 1: clabels = [[x] for x in clabels] clabels = list(zip(*clabels)) head = [] # 1) column headers for r in range(self.data.columns.nlevels): index_blanks = [ _element("th", blank_class, blank_value, not self.hidden_index) ] * (self.data.index.nlevels - 1) name = self.data.columns.names[r] column_name = [ _element( "th", f"{blank_class if name is None else index_name_class} level{r}", name if name is not None else blank_value, not self.hidden_index, ) ] if clabels: column_headers = [ _element( "th", f"{col_heading_class} level{r} col{c}", value, _is_visible(c, r, col_lengths), attributes=(f'colspan="{col_lengths.get((r, c), 0)}"' if col_lengths.get((r, c), 0) > 1 else ""), ) for c, value in enumerate(clabels[r]) ] head.append(index_blanks + column_name + column_headers) # 2) index names if (self.data.index.names and com.any_not_none(*self.data.index.names) and not self.hidden_index): index_names = [ _element( "th", f"{index_name_class} level{c}", blank_value if name is None else name, True, ) for c, name in enumerate(self.data.index.names) ] column_blanks = [ _element( "th", f"{blank_class} col{c}", blank_value, c not in self.hidden_columns, ) for c in range(len(clabels[0])) ] head.append(index_names + column_blanks) return head
def _translate(self): """ Convert the DataFrame in `self.data` and the attrs from `_build_styles` into a dictionary of {head, body, uuid, cellstyle}. """ ROW_HEADING_CLASS = "row_heading" COL_HEADING_CLASS = "col_heading" INDEX_NAME_CLASS = "index_name" DATA_CLASS = "data" BLANK_CLASS = "blank" BLANK_VALUE = " " # mapping variables ctx = self.ctx # td css styles from apply() and applymap() cell_context = self.cell_context # td css classes from set_td_classes() cellstyle_map: DefaultDict[tuple[CSSPair, ...], list[str]] = defaultdict(list) # copied attributes hidden_index = self.hidden_index hidden_columns = self.hidden_columns # construct render dict d = { "uuid": self.uuid, "table_styles": _format_table_styles(self.table_styles or []), "caption": self.caption, } # for sparsifying a MultiIndex idx_lengths = _get_level_lengths(self.index) col_lengths = _get_level_lengths(self.columns, hidden_columns) n_rlvls = self.data.index.nlevels n_clvls = self.data.columns.nlevels rlabels = self.data.index.tolist() clabels = self.data.columns.tolist() if n_rlvls == 1: rlabels = [[x] for x in rlabels] if n_clvls == 1: clabels = [[x] for x in clabels] clabels = list(zip(*clabels)) head = [] for r in range(n_clvls): # Blank for Index columns... row_es = [ { "type": "th", "value": BLANK_VALUE, "display_value": BLANK_VALUE, "is_visible": not hidden_index, "class": " ".join([BLANK_CLASS]), } ] * (n_rlvls - 1) # ... except maybe the last for columns.names name = self.data.columns.names[r] cs = [ BLANK_CLASS if name is None else INDEX_NAME_CLASS, f"level{r}", ] name = BLANK_VALUE if name is None else name row_es.append( { "type": "th", "value": name, "display_value": name, "class": " ".join(cs), "is_visible": not hidden_index, } ) if clabels: for c, value in enumerate(clabels[r]): es = { "type": "th", "value": value, "display_value": value, "class": f"{COL_HEADING_CLASS} level{r} col{c}", "is_visible": _is_visible(c, r, col_lengths), } colspan = col_lengths.get((r, c), 0) if colspan > 1: es["attributes"] = f'colspan="{colspan}"' row_es.append(es) head.append(row_es) if ( self.data.index.names and com.any_not_none(*self.data.index.names) and not hidden_index ): index_header_row = [] for c, name in enumerate(self.data.index.names): cs = [INDEX_NAME_CLASS, f"level{c}"] name = "" if name is None else name index_header_row.append( {"type": "th", "value": name, "class": " ".join(cs)} ) index_header_row.extend( [ { "type": "th", "value": BLANK_VALUE, "class": " ".join([BLANK_CLASS, f"col{c}"]), } for c in range(len(clabels[0])) if c not in hidden_columns ] ) head.append(index_header_row) d.update({"head": head}) body = [] for r, row_tup in enumerate(self.data.itertuples()): row_es = [] for c, value in enumerate(rlabels[r]): rid = [ ROW_HEADING_CLASS, f"level{c}", f"row{r}", ] es = { "type": "th", "is_visible": (_is_visible(r, c, idx_lengths) and not hidden_index), "value": value, "display_value": value, "id": "_".join(rid[1:]), "class": " ".join(rid), } rowspan = idx_lengths.get((c, r), 0) if rowspan > 1: es["attributes"] = f'rowspan="{rowspan}"' row_es.append(es) for c, value in enumerate(row_tup[1:]): formatter = self._display_funcs[(r, c)] row_dict = { "type": "td", "value": value, "display_value": formatter(value), "is_visible": (c not in hidden_columns), "attributes": "", } # only add an id if the cell has a style props: CSSList = [] if self.cell_ids or (r, c) in ctx: row_dict["id"] = f"row{r}_col{c}" props.extend(ctx[r, c]) # add custom classes from cell context cls = "" if (r, c) in cell_context: cls = " " + cell_context[r, c] row_dict["class"] = f"{DATA_CLASS} row{r} col{c}{cls}" row_es.append(row_dict) if props: # (), [] won't be in cellstyle_map, cellstyle respectively cellstyle_map[tuple(props)].append(f"row{r}_col{c}") body.append(row_es) d.update({"body": body}) cellstyle: list[dict[str, CSSList | list[str]]] = [ {"props": list(props), "selectors": selectors} for props, selectors in cellstyle_map.items() ] d.update({"cellstyle": cellstyle}) table_attr = self.table_attributes use_mathjax = get_option("display.html.use_mathjax") if not use_mathjax: table_attr = table_attr or "" if 'class="' in table_attr: table_attr = table_attr.replace('class="', 'class="tex2jax_ignore ') else: table_attr += ' class="tex2jax_ignore"' d.update({"table_attributes": table_attr}) if self.tooltips: d = self.tooltips._translate(self.data, self.uuid, d) return d
def _translate_header( self, blank_class: str, blank_value: str, index_name_class: str, col_heading_class: str, sparsify_cols: bool, max_cols: int, trimmed_col_class: str, ): """ Build each <tr> within table <head> as a list Using the structure: +----------------------------+---------------+---------------------------+ | index_blanks ... | column_name_0 | column_headers (level_0) | 1) | .. | .. | .. | | index_blanks ... | column_name_n | column_headers (level_n) | +----------------------------+---------------+---------------------------+ 2) | index_names (level_0 to level_n) ... | column_blanks ... | +----------------------------+---------------+---------------------------+ Parameters ---------- blank_class : str CSS class added to elements within blank sections of the structure. blank_value : str HTML display value given to elements within blank sections of the structure. index_name_class : str CSS class added to elements within the index_names section of the structure. col_heading_class : str CSS class added to elements within the column_names section of structure. sparsify_cols : bool Whether column_headers section will add colspan attributes (>1) to elements. max_cols : int Maximum number of columns to render. If exceeded will contain `...` filler. trimmed_col_class : str CSS class added to elements within a column including `...` trimmed vals. Returns ------- head : list The associated HTML elements needed for template rendering. """ # for sparsifying a MultiIndex col_lengths = _get_level_lengths(self.columns, sparsify_cols, max_cols, self.hidden_columns) clabels = self.data.columns.tolist( )[:max_cols] # slice to allow trimming if self.data.columns.nlevels == 1: clabels = [[x] for x in clabels] clabels = list(zip(*clabels)) head = [] # 1) column headers for r in range(self.data.columns.nlevels): index_blanks = [ _element("th", blank_class, blank_value, not self.hidden_index) ] * (self.data.index.nlevels - 1) name = self.data.columns.names[r] column_name = [ _element( "th", f"{blank_class if name is None else index_name_class} level{r}", name if name is not None else blank_value, not self.hidden_index, ) ] if clabels: column_headers = [ _element( "th", f"{col_heading_class} level{r} col{c}", value, _is_visible(c, r, col_lengths), attributes=(f'colspan="{col_lengths.get((r, c), 0)}"' if col_lengths.get((r, c), 0) > 1 else ""), ) for c, value in enumerate(clabels[r]) ] if len(self.data.columns) > max_cols: # add an extra column with `...` value to indicate trimming column_headers.append( _element( "th", f"{col_heading_class} level{r} {trimmed_col_class}", "...", True, attributes="", )) head.append(index_blanks + column_name + column_headers) # 2) index names if (self.data.index.names and com.any_not_none(*self.data.index.names) and not self.hidden_index): index_names = [ _element( "th", f"{index_name_class} level{c}", blank_value if name is None else name, True, ) for c, name in enumerate(self.data.index.names) ] if len(self.data.columns) <= max_cols: blank_len = len(clabels[0]) else: blank_len = len( clabels[0]) + 1 # to allow room for `...` trim col column_blanks = [ _element( "th", f"{blank_class} col{c}", blank_value, c not in self.hidden_columns, ) for c in range(blank_len) ] head.append(index_names + column_blanks) return head