def test_get_standard_colors_default_num_colors(self): from pandas.plotting._matplotlib.style import get_standard_colors # Make sure the default color_types returns the specified amount color1 = get_standard_colors(1, color_type="default") color2 = get_standard_colors(9, color_type="default") color3 = get_standard_colors(20, color_type="default") assert len(color1) == 1 assert len(color2) == 9 assert len(color3) == 20
def test_standard_colors_all(self): import matplotlib.colors as colors from pandas.plotting._matplotlib.style import get_standard_colors # multiple colors like mediumaquamarine for c in colors.cnames: result = get_standard_colors(num_colors=1, color=c) assert result == [c] result = get_standard_colors(num_colors=1, color=[c]) assert result == [c] result = get_standard_colors(num_colors=3, color=c) assert result == [c] * 3 result = get_standard_colors(num_colors=3, color=[c]) assert result == [c] * 3 # single letter colors like k for c in colors.ColorConverter.colors: result = get_standard_colors(num_colors=1, color=c) assert result == [c] result = get_standard_colors(num_colors=1, color=[c]) assert result == [c] result = get_standard_colors(num_colors=3, color=c) assert result == [c] * 3 result = get_standard_colors(num_colors=3, color=[c]) assert result == [c] * 3
def test_standard_colors(self, c): from pandas.plotting._matplotlib.style import get_standard_colors result = get_standard_colors(1, color=c) assert result == [c] result = get_standard_colors(1, color=[c]) assert result == [c] result = get_standard_colors(3, color=c) assert result == [c] * 3 result = get_standard_colors(3, color=[c]) assert result == [c] * 3
def test_standard_colors(self): from pandas.plotting._matplotlib.style import get_standard_colors for c in ["r", "red", "green", "#FF0000"]: result = get_standard_colors(1, color=c) assert result == [c] result = get_standard_colors(1, color=[c]) assert result == [c] result = get_standard_colors(3, color=c) assert result == [c] * 3 result = get_standard_colors(3, color=[c]) assert result == [c] * 3
def _validate_color_args(self): if "color" in self.kwds: if self.colormap is not None: warnings.warn( "'color' and 'colormap' cannot be used " "simultaneously. Using 'color'" ) self.color = self.kwds.pop("color") if isinstance(self.color, dict): valid_keys = ["boxes", "whiskers", "medians", "caps"] for key in self.color: if key not in valid_keys: raise ValueError( f"color dict contains invalid key '{key}'. " f"The key must be either {valid_keys}" ) else: self.color = None # get standard colors for default colors = get_standard_colors(num_colors=3, colormap=self.colormap, color=None) # use 2 colors by default, for box/whisker and median # flier colors isn't needed here # because it can be specified by ``sym`` kw self._boxes_c = colors[0] self._whiskers_c = colors[0] self._medians_c = colors[2] self._caps_c = colors[0]
def _get_colors(): # num_colors=3 is required as method maybe_color_bp takes the colors # in positions 0 and 2. # if colors not provided, use same defaults as DataFrame.plot.box result = get_standard_colors(num_colors=3) result = np.take(result, [0, 0, 2]) result = np.append(result, "k") colors = kwds.pop("color", None) if colors: if is_dict_like(colors): # replace colors in result array with user-specified colors # taken from the colors dict parameter # "boxes" value placed in position 0, "whiskers" in 1, etc. valid_keys = ["boxes", "whiskers", "medians", "caps"] key_to_index = dict(zip(valid_keys, range(4))) for key, value in colors.items(): if key in valid_keys: result[key_to_index[key]] = value else: raise ValueError( f"color dict contains invalid key '{key}'. " f"The key must be either {valid_keys}" ) else: result.fill(colors) return result
def test_get_standard_colors_random_seed(self): # GH17525 df = DataFrame(np.zeros((10, 10))) # Make sure that the np.random.seed isn't reset by get_standard_colors plotting.parallel_coordinates(df, 0) rand1 = np.random.random() plotting.parallel_coordinates(df, 0) rand2 = np.random.random() assert rand1 != rand2 # Make sure it produces the same colors every time it's called from pandas.plotting._matplotlib.style import get_standard_colors color1 = get_standard_colors(1, color_type="random") color2 = get_standard_colors(1, color_type="random") assert color1 == color2
def test_default_colors_named_undefined_prop_cycle(self, num_colors, expected_name): import matplotlib as mpl import matplotlib.colors as mcolors with mpl.rc_context(rc={}): expected = [mcolors.to_hex(x) for x in expected_name] result = get_standard_colors(num_colors=num_colors) assert result == expected
def test_default_colors_named_from_prop_cycle_string(self, num_colors, expected): import matplotlib as mpl from matplotlib.pyplot import cycler mpl_params = { "axes.prop_cycle": cycler(color="bgry"), } with mpl.rc_context(rc=mpl_params): result = get_standard_colors(num_colors=num_colors) assert result == expected
def test_get_standard_colors_no_appending(self): # GH20726 # Make sure not to add more colors so that matplotlib can cycle # correctly. from matplotlib import cm from pandas.plotting._matplotlib.style import get_standard_colors color_before = cm.gnuplot(range(5)) color_after = get_standard_colors(1, color=color_before) assert len(color_after) == len(color_before) df = DataFrame(np.random.randn(48, 4), columns=list("ABCD")) color_list = cm.gnuplot(np.linspace(0, 1, 16)) p = df.A.plot.bar(figsize=(16, 7), color=color_list) assert p.patches[1].get_facecolor() == p.patches[17].get_facecolor()
def plot_multi(data, cols=None, spacing=.1, **kwargs): """ 帮助快速绘画出多个图 从网上找的 QAQ 好用 data: DataFrame cols: 列表 """ from pandas.plotting._matplotlib.style import get_standard_colors from pandas import plotting # Get default color style from pandas - can be changed to any other color list if cols is None: cols = data.columns if len(cols) == 0: return try: colors = getattr( getattr(plotting, '_matplotlib').style, '_get_standard_colors')(num_colors=len(cols)) except AttributeError: colors = get_standard_colors(num_colors=len(cols)) except Exception: raise ValueError("版本错误无法获取颜色") # First axis ax = data.loc[:, cols[0]].plot(label=cols[0], color=colors[0], **kwargs) ax.set_ylabel(ylabel=cols[0]) lines, labels = ax.get_legend_handles_labels() for n in range(1, len(cols)): # Multiple y-axes ax_new = ax.twinx() ax_new.spines['right'].set_position(('axes', 1 + spacing * (n - 1))) data.loc[:, cols[n]].plot(ax=ax_new, label=cols[n], color=colors[n % len(colors)]) ax_new.set_ylabel(ylabel=cols[n]) # Proper legend position line, label = ax_new.get_legend_handles_labels() lines += line labels += label ax.legend(lines, labels, loc=0) return ax
def plot_multi(data, cols=None, spacing=.06, color_map=None, plot_kw=None, **kwargs): """ Plot data with multiple scaels together Args: data: DataFrame of data cols: columns to be plotted spacing: spacing between legends color_map: customized colors in map plot_kw: kwargs for each plot **kwargs: kwargs for the first plot Returns: ax for plot """ from pandas.plotting._matplotlib.style import get_standard_colors if cols is None: cols = data.columns if plot_kw is None: plot_kw = [{}] * len(cols) if len(cols) == 0: return num_colors = len(utils.flatten(cols)) # Get default color style from pandas colors = get_standard_colors(num_colors=num_colors) if color_map is None: color_map = dict() fig = plt.figure() ax, lines, labels, c_idx = None, [], [], 0 for n, col in enumerate(cols): if isinstance(col, (list, tuple)): ylabel = ' / '.join(cols[n]) color = [ color_map.get(cols[n][_ - c_idx], colors[_ % len(colors)]) for _ in range(c_idx, c_idx + len(cols[n])) ] c_idx += len(col) else: ylabel = col color = color_map.get(col, colors[c_idx % len(colors)]) c_idx += 1 if 'color' in plot_kw[n]: color = plot_kw[n].pop('color') if ax is None: # First y-axes legend = plot_kw[0].pop('legend', kwargs.pop('legend', False)) ax = data.loc[:, col].plot( label=col, color=color, legend=legend, zorder=n, **plot_kw[0], **kwargs ) ax.set_ylabel(ylabel=ylabel) line, label = ax.get_legend_handles_labels() ax.spines['left'].set_edgecolor('#D5C4A1') ax.spines['left'].set_alpha(.5) else: # Multiple y-axes legend = plot_kw[n].pop('legend', False) ax_new = ax.twinx() ax_new.spines['right'].set_position(('axes', 1 + spacing * (n - 1))) data.loc[:, col].plot( ax=ax_new, label=col, color=color, legend=legend, zorder=n, **plot_kw[n] ) ax_new.set_ylabel(ylabel=ylabel) line, label = ax_new.get_legend_handles_labels() ax_new.spines['right'].set_edgecolor('#D5C4A1') ax_new.spines['right'].set_alpha(.5) ax_new.grid(False) # Proper legend position lines += line labels += label fig.legend(lines, labels, loc=8, prop=dict(), ncol=num_colors).set_zorder(len(cols)) ax.set_xlabel(' \n ') return ax
def test_user_input_color_floats(self, num_colors, expected): color = (0.1, 0.2, 0.3) result = get_standard_colors(color=color, num_colors=num_colors) assert result == expected
def parallel_coordinates( frame: DataFrame, class_column, cols=None, ax: Axes | None = None, color=None, use_columns=False, xticks=None, colormap=None, axvlines: bool = True, axvlines_kwds=None, sort_labels: bool = False, **kwds, ) -> Axes: import matplotlib.pyplot as plt if axvlines_kwds is None: axvlines_kwds = {"linewidth": 1, "color": "black"} n = len(frame) classes = frame[class_column].drop_duplicates() class_col = frame[class_column] if cols is None: df = frame.drop(class_column, axis=1) else: df = frame[cols] used_legends: set[str] = set() ncols = len(df.columns) # determine values to use for xticks if use_columns is True: if not np.all(np.isreal(list(df.columns))): raise ValueError("Columns must be numeric to be used as xticks") x = df.columns elif xticks is not None: if not np.all(np.isreal(xticks)): raise ValueError("xticks specified must be numeric") elif len(xticks) != ncols: raise ValueError("Length of xticks must match number of columns") x = xticks else: x = list(range(ncols)) if ax is None: ax = plt.gca() color_values = get_standard_colors( num_colors=len(classes), colormap=colormap, color_type="random", color=color ) if sort_labels: classes = sorted(classes) color_values = sorted(color_values) colors = dict(zip(classes, color_values)) for i in range(n): y = df.iloc[i].values kls = class_col.iat[i] label = pprint_thing(kls) if label not in used_legends: used_legends.add(label) ax.plot(x, y, color=colors[kls], label=label, **kwds) else: ax.plot(x, y, color=colors[kls], **kwds) if axvlines: for i in x: ax.axvline(i, **axvlines_kwds) ax.set_xticks(x) ax.set_xticklabels(df.columns) ax.set_xlim(x[0], x[-1]) ax.legend(loc="upper right") ax.grid() return ax
def test_empty_color_raises(self, color): with pytest.raises(ValueError, match="Invalid color argument"): get_standard_colors(color=color, num_colors=1)
def radviz( frame: DataFrame, class_column, ax: Axes | None = None, color=None, colormap=None, **kwds, ) -> Axes: import matplotlib.pyplot as plt def normalize(series): a = min(series) b = max(series) return (series - a) / (b - a) n = len(frame) classes = frame[class_column].drop_duplicates() class_col = frame[class_column] df = frame.drop(class_column, axis=1).apply(normalize) if ax is None: ax = plt.gca() ax.set_xlim(-1, 1) ax.set_ylim(-1, 1) to_plot: dict[Hashable, list[list]] = {} colors = get_standard_colors( num_colors=len(classes), colormap=colormap, color_type="random", color=color ) for kls in classes: to_plot[kls] = [[], []] m = len(frame.columns) - 1 s = np.array( [(np.cos(t), np.sin(t)) for t in [2 * np.pi * (i / m) for i in range(m)]] ) for i in range(n): row = df.iloc[i].values row_ = np.repeat(np.expand_dims(row, axis=1), 2, axis=1) y = (s * row_).sum(axis=0) / row.sum() kls = class_col.iat[i] to_plot[kls][0].append(y[0]) to_plot[kls][1].append(y[1]) for i, kls in enumerate(classes): ax.scatter( to_plot[kls][0], to_plot[kls][1], color=colors[i], label=pprint_thing(kls), **kwds, ) ax.legend() ax.add_patch(patches.Circle((0.0, 0.0), radius=1.0, facecolor="none")) for xy, name in zip(s, df.columns): ax.add_patch(patches.Circle(xy, radius=0.025, facecolor="gray")) if xy[0] < 0.0 and xy[1] < 0.0: ax.text( xy[0] - 0.025, xy[1] - 0.025, name, ha="right", va="top", size="small" ) elif xy[0] < 0.0 and xy[1] >= 0.0: ax.text( xy[0] - 0.025, xy[1] + 0.025, name, ha="right", va="bottom", size="small", ) elif xy[0] >= 0.0 and xy[1] < 0.0: ax.text( xy[0] + 0.025, xy[1] - 0.025, name, ha="left", va="top", size="small" ) elif xy[0] >= 0.0 and xy[1] >= 0.0: ax.text( xy[0] + 0.025, xy[1] + 0.025, name, ha="left", va="bottom", size="small" ) ax.axis("equal") return ax
def plot_multi_axis(df: pd.DataFrame, cols: Optional[List[str]] = None, spacing: float = .1, colored_axes: bool = True, axis_locations_in_legend: bool = True, legend_kwargs: Optional[Dict[str, Any]] = None, **kwargs) -> plt.Axes: """ Plot multiple series with different y-axes Adapted from https://stackoverflow.com/a/50655786 :param df: Data to be plotted :param cols: subset of columns to plot :param spacing: Amount of space between y-axes beyond the two which are on the sides of the box :param colored_axes: Whether to make axis labels and ticks colored the same as the line on the graph :param axis_locations_in_legend: Whether to add to the legend which axis corresponds to which plot :param legend_kwargs: Keyword arguments to pass to ax.legend :param kwargs: df.plot kwargs :return: """ if cols is None: cols = df.columns if len(cols) == 0: raise ValueError('if cols are passed, must not be an empty list') if legend_kwargs is None: legend_kwargs = {} if axis_locations_in_legend: rename_dict: Dict[str, str] = {} for i, col in enumerate(cols): if i == 0: base_position = 'left' extra_position = '' else: base_position = 'right' extra_position = f', {ordinal(i)}' position = base_position + extra_position new_name = f'{col} ({position})' rename_dict[col] = new_name df = df.rename(columns=rename_dict) col_labels = cols cols = list(rename_dict.values()) else: col_labels = cols # Get default color style from pandas - can be changed to any other color list colors = get_standard_colors(num_colors=len(cols)) # First axis color = colors[0] ax = df.loc[:, cols[0]].plot(label=cols[0], color=color, **kwargs) ax.set_ylabel(ylabel=col_labels[0]) if colored_axes: ax.yaxis.label.set_color(color) ax.tick_params(axis='y', colors=color) lines, labels = ax.get_legend_handles_labels() for n in range(1, len(cols)): color = colors[n % len(colors)] # Multiple y-axes ax_new: plt.Axes = ax.twinx() ax_new.spines['right'].set_position(('axes', 1 + spacing * (n - 1))) df.loc[:, cols[n]].plot(ax=ax_new, label=cols[n], color=color, **kwargs) ax_new.set_ylabel(ylabel=col_labels[n]) if colored_axes: ax_new.yaxis.label.set_color(color) ax_new.tick_params(axis='y', colors=color) # Proper legend position line, label = ax_new.get_legend_handles_labels() lines += line labels += label ax.legend(lines, labels, **legend_kwargs) return ax
def test_user_input_color_sequence(self, num_colors, expected): color = ["red", "green", (0.1, 0.2, 0.3)] result = get_standard_colors(color=color, num_colors=num_colors) assert result == expected
def test_bad_color_raises(self, color): with pytest.raises(ValueError, match="Invalid color"): get_standard_colors(color=color, num_colors=5)
def andrews_curves( frame: DataFrame, class_column, ax: Axes | None = None, samples: int = 200, color=None, colormap=None, **kwds, ) -> Axes: import matplotlib.pyplot as plt def function(amplitudes): def f(t): x1 = amplitudes[0] result = x1 / np.sqrt(2.0) # Take the rest of the coefficients and resize them # appropriately. Take a copy of amplitudes as otherwise numpy # deletes the element from amplitudes itself. coeffs = np.delete(np.copy(amplitudes), 0) coeffs = np.resize(coeffs, (int((coeffs.size + 1) / 2), 2)) # Generate the harmonics and arguments for the sin and cos # functions. harmonics = np.arange(0, coeffs.shape[0]) + 1 trig_args = np.outer(harmonics, t) result += np.sum( coeffs[:, 0, np.newaxis] * np.sin(trig_args) + coeffs[:, 1, np.newaxis] * np.cos(trig_args), axis=0, ) return result return f n = len(frame) class_col = frame[class_column] classes = frame[class_column].drop_duplicates() df = frame.drop(class_column, axis=1) t = np.linspace(-np.pi, np.pi, samples) used_legends: set[str] = set() color_values = get_standard_colors( num_colors=len(classes), colormap=colormap, color_type="random", color=color ) colors = dict(zip(classes, color_values)) if ax is None: ax = plt.gca() ax.set_xlim(-np.pi, np.pi) for i in range(n): row = df.iloc[i].values f = function(row) y = f(t) kls = class_col.iat[i] label = pprint_thing(kls) if label not in used_legends: used_legends.add(label) ax.plot(t, y, color=colors[kls], label=label, **kwds) else: ax.plot(t, y, color=colors[kls], **kwds) ax.legend(loc="upper right") ax.grid() return ax
sys.path.append(path.join(BASE_PATH, 'src')) def root_path(file_path: str) -> str: return path.join(BASE_PATH, file_path) from file_manager import ensure_path, get_timestamp pd.set_option('display.max_columns', 500) pd.set_option('display.width', 1000) plt.rcParams.update({ 'text.usetex': True, 'font.family': 'serif', 'font.serif': 'CMU Serif' }) colors = get_standard_colors(num_colors=10) MIN_ENTRY_LIMIT = 4 MAX_ENTRY_LIMIT = 1000 timestamp_cache = {} def cache_timestamp(s: str) -> datetime: if s in timestamp_cache: timestamp = timestamp_cache[s] else: timestamp = get_timestamp(s) timestamp_cache[s] = timestamp
def test_user_input_named_color_string(self, color, num_colors, expected): result = get_standard_colors(color=color, num_colors=num_colors) assert result == expected