Изменить стиль линии matplotlib в середине графика

Я отображаю некоторые данные (две линии) и хочу изменить стиль линий для тех частей линий, где разница между ними статистически значима. Итак, на изображении ниже (теперь это ссылка b/c, политика защиты от спама не позволяет мне публиковать изображение) я бы хотел, чтобы линии выглядели по-разному (например, пунктирными) до тех пор, пока они не начнут сходиться примерно на 35°. ось х.

линейный график

Есть ли способ сделать это легко? У меня есть значения для оси x, где различия значительны, я просто не понимаю, как изменить стили линий в определенных местах оси x.


person Sceeerutinizer    schedule 14.02.2012    source источник
comment
Как насчет создания двух графиков на кривую? Один с первым набором точек (до того, как значения начнут сходиться), а затем еще один со вторым набором. Просто установите для графиков одинаковый стиль (цвет, маркер и т. д.), за исключением стиля линии! :)   -  person Ricardo Cárdenes    schedule 15.02.2012
comment
Спасибо, я попробую это. У меня есть несколько других графиков, где линии снова расходятся позже, циклически теряя значение. Это будет означать, что у меня будет куча сюжетных команд, но, надеюсь, я смогу разобраться.   -  person Sceeerutinizer    schedule 15.02.2012
comment
@RicardoCardenes- я предлагаю вам поместить свой комментарий в качестве ответа, чтобы за него можно было проголосовать / принять. Это правильный способ сделать это :-)   -  person David Robinson    schedule 15.02.2012
comment
Вы можете многое автоматизировать. Смотрите мой ответ.   -  person Ricardo Cárdenes    schedule 15.02.2012
comment
@DavidRobinson: Я знаю, я знаю, я не получил +2k просто за комментарий ;). Просто иногда мне кажется, что мой комментарий не стоит ответа :)   -  person Ricardo Cárdenes    schedule 15.02.2012
comment
Ха-ха, под правильным способом я имел в виду, что ваш ответ был правильным и должен быть официальным ответом, а не то, что публикация в качестве ответа - правильный способ сделать это. (И если мы собираемся стать конкурентоспособными, ваши +2k чуть меньше моих +2k :-)   -  person David Robinson    schedule 15.02.2012


Ответы (2)


Редактировать: у меня это было открыто и ушло, поэтому я не заметил ответа @Ricardo. Поскольку matplotlib будет преобразовывать вещи в массивы numpy в любом случае, есть более эффективные способы сделать это.

Например:

Просто начертите две разные линии, одну со стилем пунктирной линии, а другую со стилем сплошной линии.

E.g.

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y1 = 2 * x
y2 = 3 * x

xthresh = 4.5
diff = np.abs(y1 - y2)
below = diff < xthresh
above = diff >= xthresh

# Plot lines below threshold as dotted...
plt.plot(x[below], y1[below], 'b--')
plt.plot(x[below], y2[below], 'g--')

# Plot lines above threshold as solid...
plt.plot(x[above], y1[above], 'b-')
plt.plot(x[above], y2[above], 'g-')

plt.show()

введите здесь описание изображения

В случае, когда они циклические, используйте маскированные массивы:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
y1 = 2 * np.cos(x)
y2 = 3 * np.sin(x)

xthresh = 2.0
diff = np.abs(y1 - y2)
below = diff < xthresh
above = diff >= xthresh

# Plot lines below threshold as dotted...
plt.plot(np.ma.masked_where(below, x), np.ma.masked_where(below, y1), 'b--')
plt.plot(np.ma.masked_where(below, x), np.ma.masked_where(below, y2), 'g--')

# Plot lines above threshold as solid...
plt.plot(np.ma.masked_where(above, x), np.ma.masked_where(above, y1), 'b-')
plt.plot(np.ma.masked_where(above, x), np.ma.masked_where(above, y2), 'g-')

plt.show()

введите здесь описание изображения

person Joe Kington    schedule 14.02.2012
comment
Думал о чем-то подобном, но как-то решил сделать комплексно :D. Отлично :) - person Ricardo Cárdenes; 15.02.2012
comment
Рад, что только что обновил это. Просто рассматривал возможность использования замаскированного массива. Очень полезно. Спасибо всем за понимание. - person Sceeerutinizer; 15.02.2012
comment
stackoverflow.com/questions/27082282/ - person Ohm; 22.11.2014
comment
Здравствуйте, не могли бы вы уточнить, что делает строка plt.plot(x[below], y1[below], 'b--')? - person Ohm; 25.11.2014
comment
@Ohm - он использует логическое индексирование numpy (below - это логический массив, например [True, True, False, False, True]), чтобы выбрать только области x и y, где diff < xthresh. Например, если x = np.arange(10), а мы сделали print x[x < 5], то получим [0, 1, 2, 3, 4]. Однако это предполагает, что у нас есть линия с большим количеством образцов. Если у вас есть x = array([0, 1]), а вы сделали x[x < 0.5], вы просто получите 0, а не [0, 0.499999]. Это просто выбор дискретных точек, где данное условие верно, а не интерполяция. - person Joe Kington; 25.11.2014
comment
@JoeKington - Можно ли проделать тот же трюк с контурными картами? Я пытался использовать это, используя эту строку - 'lt.contour(X[stable],Y[stable], f1[stable], level=[0],colors=('r'),linewidths=4,extend=' оба')', но выдает TypeError: Input z должен быть двумерным массивом - person Ohm; 30.11.2014
comment
@Ohm - Да, но вместо этого вам нужно использовать маскированные массивы. Вот простой пример: gist.github.com/joferkington/3ca60b0b05b7310f09e8 - person Joe Kington; 02.12.2014

Допустим, ваши данные находятся в массивах NumPy dataset1 и dataset2, и вы определили threshold как свою значимость.

def group(data):
    """Assumes that len(data) > 0"""
    prev = 0
    index = 1
    value = data[0]

    while (index < len(data)):
        if data[index] != value:
            yield (value, prev, index)

            value = not value
            prev = index
        index += 1

    yield (value, prev, index)

diff = np.abs(dataset1 - dataset2)
for significant, start, end in group(diff < threshold):
   # Plot data from dataset1[start:end] and dataset2[start:end]
   # Use the value in "significant" (True/False) to figure out
   # The style
person Ricardo Cárdenes    schedule 14.02.2012
comment
Я думаю, я мог бы сделать это короче, используя что-то из itertools, но я думаю, что этого достаточно :P - person Ricardo Cárdenes; 15.02.2012