Невозможно установить цвет фона на графике в соответствии с видимыми значениями тиков - PullRequest
1 голос
/ 18 апреля 2020

Я хочу сделать график, похожий на финансовые графики Yahoo , где цвет фона отображается серым цветом через чередующиеся интервалы в соответствии с отметками даты на отметках оси. После ответа от аналогичной проблемы я получаю изображение, подобное этому:

enter image description here

Используя этот код:

n = 1000
xs = np.random.randn(n).cumsum()

plt.plot(xs)
plt.autoscale(enable=True, axis='both', tight=True)

for i in range(0, len(y_series), 400):
  plt.axvspan(i, i+100, facecolor='grey', alpha=0.5)

Однако проблема с этим кодом заключается в том, что мы используем ввод данных в качестве справочного материала для определения серой области. Вместо этого я хочу, чтобы область, выделенная серым цветом, определялась по видимым меткам на оси x или y, отделенным от входных данных. Я не хочу использовать функции локатора, потому что это также победило цель «автоматического» затенения фона в соответствии с видимыми значениями тиков. Кроме того, мы использовали целые числа по оси X, но в идеале это должно работать для дат, чисел с плавающей запятой и других.

Вот пример использования дат без заштрихованных областей:

enter image description here

Производится с этим кодом и без автомасштабирования:

n = 700
x_series = pd.date_range(start='2017-01-01', periods=n, freq='D')
y_series = np.random.randn(n).cumsum()

fig, ax = plt.subplots()
ax.plot(x_series, y_series)
plt.gcf().autofmt_xdate()

PS: я попытался прочитать список стиков, но этот список не отражает в точности видимый значения, если автомасштабируется, если выключен.

locs, labels = plt.xticks()
print(locs)

[- 200. 0. 200. 400. 600. 800. 1000. 1200.]

Спасибо за любую помощь! =)

Ответы [ 3 ]

3 голосов
/ 18 апреля 2020

Я думаю, что эта проблема немного сложная, потому что все случаи утомительны. Это правда, что xticks иногда возвращает значения слева и справа от xlim, но это только начало. Что произойдет, если данные выходят за крайний правый xtick или начинаются до крайнего левого xtick и т. Д. c?

Например, во многих случаях, указанных ниже, я хочу запустить (или остановить) полос в xmin или xmax, потому что, если я не сделаю этого, и индексирование пропустит полосы после начала (или остановки) тиков, будет длинный раздел, который не будет разбит, и он не будет выглядеть правильно.

Так что, играя с несколькими различными угловыми случаями, я остановился на этом как на покрытии (по крайней мере) тех, которые я пробовал:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(100, 11000, 7500)
y = x * np.sin(0.001*x) ** 2

def alt_bands(x):
    locs, labels = plt.xticks()
    x_left, x_right = plt.xlim()
    for i, loc in enumerate(locs):
        if i%2 == 1 and i<len(locs)-1 and loc<x[-1] and (loc>x_left or x[0]>x_left):
            L = max(x_left, x[0], loc)
            R = min(x_right, x[-1], locs[i+1])
            if x[0] <= L and R>L:
                plt.axvspan(L, R, facecolor='grey', alpha=0.5)

plt.plot(x, y)
alt_bands()

А вот несколько примеров графиков:

enter image description here

enter image description here

enter image description here

enter image description here

Честно говоря, это не тот ответ, которым я больше всего горжусь. Я не тщательно продумывал логи c, но вместо этого постепенно добавлял условия для работы с каждым новым угловым случаем, который я пробовал, но таким образом, который не сталкивался с предыдущим случаем. Пожалуйста, не стесняйтесь убирать это, если вы хотите продумать это. Или есть способ, который по сути своей чист?

1 голос
/ 18 апреля 2020

Поскольку комментарии кажутся слишком сложными, чтобы объяснить все, вот пример кода, включающий subplots, autoscale, autofmt_xdate и сброс xlims.

autoscale перемещает xlims , поэтому он должен быть вызван до того, как alt_bands получит и сбросит эти xlims.

При работе с вспомогательными участками большинство функций должны быть версией осей, а не версиями plt. Итак, ax.get_ticks() вместо plt.ticks() и ax.axvspan вместо plt.axvspan. autofmt_xdate изменяет полную фигуру (вращает и выравнивает даты по осям X и удаляет даты по осям X, за исключением тех, которые показаны на графиках внизу). fig.autofmt_xdate() следует вызывать после создания графика (после ax.plot) и после операций, которые могут изменить позиции тиков.

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

def alt_bands(ax=None):
    ax = ax or plt.gca()
    x_left, x_right = ax.get_xlim()
    locs = ax.get_xticks()
    for loc1, loc2 in zip(locs[::2], np.concatenate((locs, [x_right]))[1::2]):
        ax.axvspan(loc1, loc2, facecolor='black', alpha=0.2)
    ax.set_xlim(x_left, x_right)

n = 700
x_series = pd.date_range(start='2017-01-01', periods=n, freq='D')
y_series = np.random.normal(.01, 1, n).cumsum()

fig, axes = plt.subplots(ncols=2)
axes[0].plot(x_series, y_series)
axes[0].autoscale(enable=True, axis='both', tight=True)
alt_bands(axes[0])

axes[1].plot(x_series[200:400], y_series[200:400])
axes[1].autoscale(enable=True, axis='both', tight=True)
alt_bands(axes[1])

fig.autofmt_xdate()
plt.show()

example plot

0 голосов
/ 18 апреля 2020

проверьте, что код может помочь вам!

здесь axes([0.01, 0.01, 0.98, 0.90], facecolor="white", frameon=True) в facecolor вы можете изменить фон, также с шестнадцатеричным форматом '#F0F0F0' серый цвет

from matplotlib.pyplot import *
import subprocess
import sys
import re

# Selection of features following "Writing mathematical expressions" tutorial
mathtext_titles = {
    0: "Header demo",
    1: "Subscripts and superscripts",
    2: "Fractions, binomials and stacked numbers",
    3: "Radicals",
    4: "Fonts",
    5: "Accents",
    6: "Greek, Hebrew",
    7: "Delimiters, functions and Symbols"}
n_lines = len(mathtext_titles)

# Randomly picked examples
mathext_demos = {
    0: r"$W^{3\beta}_{\delta_1 \rho_1 \sigma_2} = "
       r"U^{3\beta}_{\delta_1 \rho_1} + \frac{1}{8 \pi 2} "
       r"\int^{\alpha_2}_{\alpha_2} d \alpha^\prime_2 \left[\frac{ "
       r"U^{2\beta}_{\delta_1 \rho_1} - \alpha^\prime_2U^{1\beta}_"
       r"{\rho_1 \sigma_2} }{U^{0\beta}_{\rho_1 \sigma_2}}\right]$",

    1: r"$\alpha_i > \beta_i,\ "
       r"\alpha_{i+1}^j = {\rm sin}(2\pi f_j t_i) e^{-5 t_i/\tau},\ "
       r"\ldots$",

    2: r"$\frac{3}{4},\ \binom{3}{4},\ \genfrac{}{}{0}{}{3}{4},\ "
       r"\left(\frac{5 - \frac{1}{x}}{4}\right),\ \ldots$",

    3: r"$\sqrt{2},\ \sqrt[3]{x},\ \ldots$",

    4: r"$\mathrm{Roman}\ , \ \mathit{Italic}\ , \ \mathtt{Typewriter} \ "
       r"\mathrm{or}\ \mathcal{CALLIGRAPHY}$",

    5: r"$\acute a,\ \bar a,\ \breve a,\ \dot a,\ \ddot a, \ \grave a, \ "
       r"\hat a,\ \tilde a,\ \vec a,\ \widehat{xyz},\ \widetilde{xyz},\ "
       r"\ldots$",

    6: r"$\alpha,\ \beta,\ \chi,\ \delta,\ \lambda,\ \mu,\ "
       r"\Delta,\ \Gamma,\ \Omega,\ \Phi,\ \Pi,\ \Upsilon,\ \nabla,\ "
       r"\aleph,\ \beth,\ \daleth,\ \gimel,\ \ldots$",

    7: r"$\coprod,\ \int,\ \oint,\ \prod,\ \sum,\ "
       r"\log,\ \sin,\ \approx,\ \oplus,\ \star,\ \varpropto,\ "
       r"\infty,\ \partial,\ \Re,\ \leftrightsquigarrow, \ \ldots$"}


def doall():
    # Colors used in mpl online documentation.
    mpl_blue_rvb = (191. / 255., 209. / 256., 212. / 255.)
    mpl_orange_rvb = (202. / 255., 121. / 256., 0. / 255.)
    mpl_grey_rvb = (51. / 255., 51. / 255., 51. / 255.)

    # Creating figure and axis.
    figure(figsize=(6, 7))
    axes([0.01, 0.01, 0.98, 0.90], facecolor="white", frameon=True)
    gca().set_xlim(0., 1.)
    gca().set_ylim(0., 1.)
    gca().set_title("Matplotlib's math rendering engine",
                    color=mpl_grey_rvb, fontsize=14, weight='bold')
    gca().set_xticklabels("", visible=False)
    gca().set_yticklabels("", visible=False)

    # Gap between lines in axes coords
    line_axesfrac = (1. / n_lines)

    # Plotting header demonstration formula
    full_demo = mathext_demos[0]
    annotate(full_demo,
             xy=(0.5, 1. - 0.59 * line_axesfrac),
             color=mpl_orange_rvb, ha='center', fontsize=20)

    # Plotting features demonstration formulae
    for i_line in range(1, n_lines):
        baseline = 1 - i_line * line_axesfrac
        baseline_next = baseline - line_axesfrac
        toptitle = mathtext_titles[i_line] + ":"
        fill_color = ['white', mpl_blue_rvb][i_line % 2]
        fill_between([0., 1.], [baseline, baseline],
                     [baseline_next, baseline_next],
                     color=fill_color, alpha=0.5)
        annotate(toptitle,
                 xy=(0.07, baseline - 0.3 * line_axesfrac),
                 color=mpl_grey_rvb, weight='bold')
        demo = mathext_demos[i_line]
        annotate(demo,
                 xy=(0.05, baseline - 0.75 * line_axesfrac),
                 color=mpl_grey_rvb, fontsize=16)

    for i1 in range(n_lines):
        s1 = mathext_demos[i1]
        print(i1, s1)
    show()


if __name__ == '__main__':
    if '--latex' in sys.argv:
        # Run: python mathtext_examples.py --latex
        # Need amsmath and amssymb packages.
        fd = open("mathtext_examples.ltx", "w")
        fd.write("\\documentclass{article}\n")
        fd.write("\\usepackage{amsmath, amssymb}\n")
        fd.write("\\begin{document}\n")
        fd.write("\\begin{enumerate}\n")

        for i in range(n_lines):
            s = mathext_demos[i]
            s = re.sub(r"(?<!\\)\$", "$$", s)
            fd.write("\\item %s\n" % s)

        fd.write("\\end{enumerate}\n")
        fd.write("\\end{document}\n")
        fd.close()

        subprocess.call(["pdflatex", "mathtext_examples.ltx"])
    else:
        doall()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...