23 August 2020

Задача двух осей и четырех графиков c Plotly

В части Plotly теперь у нас есть все, чтобы решить задачу двух осей и четырех графиков. Рассмотрим как это сделать.

Сначала создаем холст с двумя графиками по вертикали, указывая, что каждый будет иметь по две оси:

fig = make_subplots(rows=2, cols=1 , 

  subplot_titles = ('Upper', 'Lower'),
  specs=[[{"secondary_y":True}],[{"secondary_y":True}]])


Теперь создаем четрые точечных диаграммы - две для модельных данных и две для реальных данных:

trc1 = go.Scatter(
    x = x, y = y,
    name = 'Scatter sample',
    line = dict(color= 'green'),
    marker_symbol ='x-open',
    mode ='markers+lines'
)

trc2 = go.Scatter(
    x = x, y = y2,
    name = 'Scatter sample 2',
    line = dict(color= 'blue'),
    marker_symbol ='x-open',
    mode ='markers+lines'
)

trc1r = go.Scatter(
    x = x, y = yr,
    name = 'Scatter sample real',
    line = dict(color= 'red', dash='dot'),
    marker_symbol ='diamond-open',
    mode ='markers+lines'
)

trc2r = go.Scatter(
    x = x, y = yr2,
    name = 'Scatter sample 2 real',
    line = dict(color= 'black', dash='dot'),
    marker_symbol ='diamond-open',
    mode ='markers+lines'
)

Далее добавляем диаграммы на верхний график, указывая для второго набора ( y2 ) вторую ось:

fig.add_trace ( trc1 , row = 1, col =1, secondary_y=False )
fig.add_trace ( trc2 , row = 1, col =1, secondary_y=True )
fig.add_trace ( trc1r , row = 1, col =1, secondary_y=False )
fig.add_trace ( trc2r , row = 1, col =1, secondary_y=True )


А для реальных сделаем наоборот - укажем вторую ось для первого набора ( y ) :

fig.add_trace ( trc2 , row = 2, col =1, secondary_y=False )
fig.add_trace ( trc1 , row = 2, col =1, secondary_y=True )
fig.add_trace ( trc2r , row = 2, col =1, secondary_y=False )
fig.add_trace ( trc1r , row = 2, col =1, secondary_y=True )


Подписываем оси для верхнего графика:

fig.update_xaxes( title = 'Upper X', row =1 , col =1 )
fig.update_yaxes( title = 'Upper Primary Y' , secondary_y=False , row =1 , col =1  )
fig.update_yaxes( title = 'Upper Secondary Y' , secondary_y=True  , row =1 , col =1  )


Подписываем оси для нижнего графика:

fig.update_xaxes( title = 'Lower X', row =2 , col =1 )
fig.update_yaxes( title = 'Lower Primary Y' , secondary_y=False , row =2 , col =1  )
fig.update_yaxes( title = 'Lower Secondary Y' , secondary_y=True  , row =2 , col =1  )


А вот и результат:

Как можно видеть масштаб основных осей ( как и дополнительных осей ) на первом и втором графике - разный. А вот легенда дублируется - потому что мы ее не меняли при добавлении на нижний график.
Одноко легко убедиться, что легенды представлены по графикам - именно по этому их два набора.
То есть, скажем, если мы уберем верхнюю:

 то она убертся только на верхнем графике, а на нижнем она останется на месте. И чтобы ее убрать надо убрать вторую легенду.
Одиним словом, с помощью Plotly два графика с двумя осями также легко  отображаются.

15 August 2020

Plotly: вторая ось

Для задания второй оси в Plotly используется несколько другой подход, нежели в matplotlib - там ось не клонируется ( вызовом  twinx ), а задается ее наличии при создании холста.
Ранее мы использовали метод go.Figure для его создания, но он не принимает аргументов для определения второй оси. Поэтому надо использовать другой метод make_subplots:

from plotly.subplots import make_subplots
fig = make_subplots(specs=[[{"secondary_y":True}]])


Как можно видеть, задание второй оси регулируется параметром secondary_y, но он оборачивается в хитрый тип - список списков. Зачем так сделали разработчки Plotly - непонятно, но именно так это работает.

Далее мы также создаем две точечных диаграммы:

trc1 = go.Scatter(
    x = x, y = y,
    name = 'Scatter sample',
    line = dict(color= 'green', dash='dot'),
    marker_symbol ='diamond-open',
    mode ='markers+lines'
)

trc2 = go.Scatter(
    x = x, y = y2,
    name = 'Scatter sample 2',
    line = dict(color= 'blue', dash='dot'),
    marker_symbol ='diamond-open',
    mode ='markers+lines'
)


И при добавлении указываем на какую ось добавлять.
Первый - на основную:

fig.add_trace ( trc1 , secondary_y=False )


После этого добавления у нас появляется данные первой диаграммы:

Как можно видеть - второй оси пока еще нет.
Теперь добавляем вторую диаграмму на вторую ось:

fig.add_trace ( trc2 ,  secondary_y=True )

И вот тут ось уже появляется:

Для подписи оси X используется тот же метод: 

fig.update_xaxes( title = 'My new X axis' )

А вот для подписи осей Y уже надо указывать какую:

fig.update_yaxes( title = 'Primary Y' , secondary_y=False  )
fig.update_yaxes( title = 'Secondary Y' , secondary_y=True  )


Вот результат:


Таким образом создание второй оси в Plotly делается несколько по-другому, но тоже несложно.

13 August 2020

Юпитер и интерактивность: matplotlib наносит отетный удар

Ранее в посте Юпитер и интерактивность - темная строна я указал, что в простом случае matplotlib не работает нормально интерактивно. Однако чтобы это вернуть достаточно установить ipympl. Чтобы с гарантией это было в Юпитере - ставим через конду:

conda install -c conda-forge ipympl

Теперь это есть в системе:

Берем код из ранее упомянутого примера и добавляем в самое начало немного магии:

%matplotlib widget

А далее создаем два ползунка и кнопку, которая будет обрабатывать нажатие:

button = widgets.Button(description='My Button')

sF = widgets.FloatSlider(
         value=1,
         min=0,
         max=10.0,
         step=0.1,)
sPhase = widgets.FloatSlider(
         value=1,
         min=0,
         max=10.0,
         step=0.1,)


Теперь осталось сделать обработчик кнопки, привязать его к кнопке и разместить элементы. Для размещения я использую Vbox, то есть в нем элементы будут размещаться последовательно вертикально. Туда же в качестве виджета я помещаю и вывод - widgets.Output() :

outt = widgets.Output()

def on_butt_clicked(b):
    with outt:
        clear_output()
        global sF,sPhase
        plot_f(sF.value, sPhase.value)
       
button.on_click(on_butt_clicked)
widgets.VBox([sF, sPhase, button, outt ])


И вот теперь все начинает работать:

Меняем значение ползунка и еще раз нажимаем кнопку:

Как можно видеть, заголовок у графика поменялся с Figure 3 на Figure 4. Однако картинка осталась на месте, правильно отображенная и не стала клонироваться. Более того, как и в случае режима notebook, задаваемого магическими командами, у графика есть такая же панель инструментов, только слева, а не внизу.
Правда, если изменить масштаб/сдвинуть график, то после нажатия кнопки это все пропадет в силу того, что картинка полностью перерисовывается. Тем не менее путем доустановки отсутствующего в штатной комплктации ipympl можно использовать интерактивные возможности Юпитера и с matplotlib.

12 August 2020

Matplotlib и Юпитер: немного о магии

Решение задачи двух осей и четырех графиков всем хорошо, кроме как внешним видом - графики получились маленькие:

Варианта разрешить этот недостаток ровно два - явно поменять размер графиков или использовать магические (magic) команды. Рассмотрим их по порядку.

Чтобы изменить размер графика надо изменить параметр figsize у холста.
Если делать это без сохранения объекта холста ( figure ) то вызов будет такой:

plt.rcParams["figure.figsize"] = [10,6]

Здесь я изменил размеры по горизонтали и вертикали на 10 и 6 соответственно, когда по умолчанию эти размеры 6.4 и 4.8.
В случае использования объекта холста можно сделать это прямо при вызове subplots вот так:

fig, ( ax_up, ax_btm) = plt.subplots(2,1,figsize=(10,6))

Делать это надо до вызовов рисования. Результат будет один и тот же - график увеличится в размерах:

Эмпирическим путем можно подобрать нужный размер графика.
Второй способ подразумевает использование магических команд, которые начинаются с символа процента, для указаний работы реализации. Для библиотеки Matplotlib они начинаются так:

%matplotlib [что-то тут]

Два основных варианта это inline и notebook, то есть так:

%matplotlib inline
%matplotlib notebook


Случай inline - это как если бы мы ничего не указывали - неинтерактивный график. Нужен разве что если мы использовали notebook и хотим вернуться обратно.
А вот notebook добавляет интерактивности:

 Как можно видеть сверху появился заголовок Figure 1 с кнопкой. Эта кнопка - выключает интерактивность и если ее выключить, то более уже к ней не вернуться.

Внизу справа ( на нее показывет красная стрелка ) - символ в виде треугольника - это для изменения размеров - если на на него встать, нажать мышь и двигать, то размер будет меняться.
Внизу слева - меню управления.
Слева направо:

  • Символ в виде дома - вернуться к исходному отображению ( Home )
  • Стрелка влево - вернуться на шаг изменения назад ( Back, аналог Undo )
  • Стрелка вправо - сделать изменени вперед ( после возравщения на шаг назад, Forward, аналог Redo )
  • Крест со стрелками - смещение ( Pan )
  • Пустой квадрат - масштаб ( Zoom )
  • Символ дискеты - сохранить изображение ( Download )


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

Вот график после такого масштабирования:

При помощи сдвига можно сдвинуть график к интересующей его части - тогда курсор меняется на руку и при удержании кнопки мыши и ее перемещении двигается и сам график:

В обоих случаях - масштаба и сдвига - значения осей автоматически меняются. Стрелками влево/вправо можно двигаться между приложенными изменениями отображения, а при нажатии на домик - вернуться к оригинальному.

Сохранение изображения оиткрывает картинку в новой вкладке в браузере и его можно сохранить как файл. Одноко оно работает с ошибками - прямо после масштабирования и/или сдвига картинка показывается криво:

Исправить это можно слегка изменив размер картинки иконкой справа  и снова нажав сохранение:

Таким образом в режиме notebook можно интерактивно просматривать более детально части графиков, хотя он и отстает от возможностей Plotly.

Дополнительно можно посмотеть информацию тут Using matplotlib in jupyter notebooks - comparing methods and some tips
 

11 August 2020

Задача двух осей и четырех графиков с matplotlib: решение

До конца задачи осталось совсем немного - надо просто сложить методы для двух областей с методами для двух графиков вместе.
Если это решать последовательным методом то вот код:

# верхняя область
plt.subplot(211)
plt.plot( x,y, label='Model', marker='x')
plt.plot( x,yr ,color = 'green', marker='D', linestyle='dashed', label='Real')
plt.xlabel('X')
plt.ylabel('Y', color='red', fontsize=14)
plt.title('First Subplot', color='green', fontsize=14)
plt.legend(loc ='lower right')

plt.gca().twinx()
plt.plot( x,y2,color = 'black',label='Model Y2', marker='x')
plt.plot( x,yr2 ,color = 'red', marker='o', linestyle='dashed', label='Real Y2')
plt.ylabel('Y2')
plt.legend(loc = 'upper center')

# нижняя область
plt.subplot(212)
plt.plot( x,y, label='Model 2 ', marker='x')
plt.plot( x,yr ,color = 'green', marker='D', linestyle='dashed', label='Real 2')
plt.xlabel('X')
plt.ylabel('Y', color='red', fontsize=14)
plt.title('Second Subplot', color='green', fontsize=14)
plt.legend(loc ='lower right')

plt.gca().twinx()
plt.plot( x,y2,color = 'black',label='Model 2 Y2', marker='x')
plt.plot( x,yr2 ,color = 'red', marker='o', linestyle='dashed', label='Real 2 Y2')
plt.ylabel('Y2')
plt.legend(loc = 'upper center')
plt.subplots_adjust(hspace=0.70)


Результат выполнения:

 

Если это решать путем создания переменных для холста и для осей то вот код:

fig, ( ax_up, ax_btm) = plt.subplots(2,1)
# верхняя область
ax_up.plot( x,yr ,color = 'green', marker='D', linestyle='dashed', label='Real')
ax_up.plot( x,y, label='Model', marker='x')

ax_up.set_xlabel('X')
ax_up.set_ylabel('Y', color='red', fontsize=14)
ax_up.set_title('First Subplot', color='green', fontsize=14)
ax_up.legend(loc ='lower right')

ax_up2 = ax_up.twinx()
ax_up2.plot( x,y2,color = 'black',label='Model Y2', marker='x')
ax_up2.plot( x,yr2 ,color = 'red', marker='o', linestyle='dashed', label='Real Y2')
ax_up2.set_ylabel('Y2')
ax_up2.legend(loc = 'upper center')

# нижняя область
ax_btm.plot( x,yr ,color = 'green', marker='D', linestyle='dashed', label='Real')
ax_btm.plot( x,y, label='Model', marker='x')

ax_btm.set_xlabel('X')
ax_btm.set_ylabel('Y', color='red', fontsize=14)
ax_btm.set_title('Second Subplot', color='green', fontsize=14)
ax_btm.legend(loc ='lower right')

ax_btm2 = ax_btm.twinx()
ax_btm2.plot( x,y2,color = 'black',label='Model Y2', marker='x')
ax_btm2.plot( x,yr2 ,color = 'red', marker='o', linestyle='dashed', label='Real Y2')
ax_btm2.set_ylabel('Y2')
ax_btm2.legend(loc = 'upper center')

plt.subplots_adjust(hspace=0.70)

При этом получается такая же картинка.
Задача решена.

Задача двух осей и четырех графиков: две оси с matplotlib

Следующий этап этой задачи - создание второй оси. В matplotlib это достигается вызовом метода оси twinx, который тоже возвращает ось, только вторую. В простом случае ее можно и не запоминать - она становится текущей. Однако, чтобы ее получить в простом случае надо получить саму ось вызовом gca. При этом matplotlib не допускает интерактивности в части построения частей сложного графика.
В самом деле, давайте рассмотрим пример. Сначала создадим пару графиков - модельный и реальный - для одной оси:

plt.plot( x,y, label='Model', marker='x')
plt.plot( x,yr ,color = 'green', marker='D', linestyle='dashed', label='Real')
plt.xlabel('X')
plt.ylabel('Y', color='red', fontsize=14)
plt.title('First Subplot', color='green', fontsize=14)


Вот вывод такой части кода:

А теперь попробуем создать вторую ось в другой ячейке. Вот что мы увидим: 

Т.е. ось у нас, конечно, создалась, но график пустой - это просто другой график.
И даже если мы попытаем здесь добавить данные для втрой оси:

plt.gca().twinx()
plt.plot( x,y2,color = 'black',label='Model Y2', marker='x')
plt.plot( x,yr2 ,color = 'red', marker='o', linestyle='dashed', label='Real Y2')
plt.ylabel('Y2')


то мы увидим только их - предыдущие данные для первой оси пропадут:

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

Теперь попробуем добавить легенды графиков - их придется делать два раза ибо каждый вызов будет относиться к отдельной оси. Ранее я использовал вызов plt.legend().set_visible(True) но оказывается можно и проще - просто plt.legend(). Вот что получим:

Как можно видеть, подписи легенд перехлестнулись с графиками. Ровно как и в случае с подписями областей тут, увы, придется править руками. В вызов plt.legend() можно поставить параметр loc и указать место расположения строкой:

Более детально о подобном форматировании можно почитать тут Customizing Plot Legends

Второй вариант создания второй оси - явный вызов методов у осей. В этом случае надо создать холст и ось вызовом subplots() не передавая ему никаких параметров для разбивки по областям.
Вызов twinx в этом случае производится непосредственно у оси, далее новая ось запоминается и вызов рисования идет ее методами:

fig, ax  = plt.subplots()
ax.plot( x,yr ,color = 'green', marker='D', linestyle='dashed', label='Real')
ax.plot( x,y, label='Model', marker='x')

ax.set_xlabel('X')
ax.set_ylabel('Y', color='red', fontsize=14)
ax.set_title('First Subplot', color='green', fontsize=14)
ax.legend(loc ='lower right')

ax2 = ax.twinx()
ax2.plot( x,y2,color = 'black',label='Model Y2', marker='x')
ax2.plot( x,yr2 ,color = 'red', marker='o', linestyle='dashed', label='Real Y2')
ax2.set_ylabel('Y2')
ax2.legend(loc = 'upper center')


Данный код рисует в точности такой же график с двумя осями, как и выше.

09 August 2020

Plotly-области: немного о подписях графиков

Ранее в посте Plotly : области. Делаем два графика мы сделали два графика.

Подписи для каждого из них мы задавали прямо при разбиении областей:

fig = make_subplots(rows=2, cols=1 , subplot_titles = ('Upper', 'Lower') )

И если нам требуется изменить, скажем, подписи осей или всей диаграммы, то никаких проблем не возникнет - это вызывается так:

fig.update_yaxes( title = 'My second Y axis' , row =2 , col =1 )
fig.update_layout( title = 'My New Chart' )


Однако с подписями областей такой трюк не пройдет.  Для начала, давайте поймем где же они хранятся. Это можно сделать печатью содержимого разметки фигуры, т.е. свойства layout:

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

 

Однако Plotly предоставляет и иной способ ее поменять - по свойству элемента.

Если посмотреть описание по документации plotly.graph_objects.Figure :
 

 

то, при том что там как бы есть парамеры row/col, все равно ничего на выйдет - все указанные методы и попытки поменять подпись таким образом, не работают:

# попытка 1 - не работает
fig.update_annotations( patch= dict(text = 'Second upper test ') , row =1 , col =1)

# попытка 2 - не работает
fig.update_annotations( text = 'Second upper test ' , row =1 , col =1)

# попытка 3 - не работает
fig.update_annotations( dict(text = 'Second upper test ') , row =1 , col =1)


Однако удивительно, что работает ссылка на элемент через селектор - т.е. ему надо указать словарь со свойствами желательного элемента. Как можно видеть наиболее яркое, кроме ключей x и y, у нас только свойство text. Так и попробуем:

fig.update_annotations( text = 'Second upper test' , selector = dict(text= 'Test Upper') )

И вуаля! - это работает:

 

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


07 August 2020

Plotly : области. Делаем два графика.

 Следующим шагом мы сделаем две области, то есть построим два графика на одном холсте.
В Plotly функция для создания областей в общем-то схожая.

Для начала ее экспортируем:

from plotly.subplots import make_subplots


Далее создаем две области по вертикали, то есть одна колонка и две строчки. При создании областей можно сразу их подписать:

fig = make_subplots(rows=2, cols=1 , subplot_titles = ('Upper', 'Lower') )

Создаем две точечных диаграммы:

trc1 = go.Scatter(
    x = x, y = y,
    name = 'Scatter sample',
    line = dict(color= 'green', dash='dot'),
    marker_symbol ='diamond-open',
    mode ='markers+lines'
)
trc2 = go.Scatter(
    x = x, y = y2,
    name = 'Scatter sample 2',
    line = dict(color= 'green', dash='dot'),
    marker_symbol ='diamond-open',
    mode ='markers+lines'
)


Добавляем первую диаграмму:

fig.add_trace ( trc1 , row = 1, col =1 )


Сразу же после исполнения появляется график, но с одной диаграммой: 

Добавляем вторую диаграмму:

fig.add_trace ( trc2 , row = 2, col =1 )

Теперь отображаются уже два графика:

Осталось только подписать оси и сам график уже известным способом. Разница только в том, что для подписей осей используется ссылка на строку и колонку:

fig.update_xaxes( title = 'My new X axis' , row =1 , col =1 )
fig.update_yaxes( title = 'My new Y axis' , row =1 , col =1 )
fig.update_xaxes( title = 'My second X axis' , row =2 , col =1 )
fig.update_yaxes( title = 'My second Y axis' , row =2 , col =1 )
fig.update_layout( title = 'My New Chart' )


Вот и результат:

 

Таким образом по сравнению с matplotlib использование Plotly не сильно сложнее  - разве что создание самого графика несколько более длиннее в записи  go.Scatter по сравению с plot.
C другой стороны не требуется настройка вертикальных отступов посредством subplots_adust и библиотека отступы сама отлично настраивает.

04 August 2020

Plotly : шаблоны

В предыдущем посте Plotly : подписи у графика и осей мы нашли нужные нам ссылки по смыслу в параметре template т.е. в шаблоне.
А что если попробовать применить сам шаблон ?

Для изменения, к примеру, вызовем вот так:

fig.layout.update( template = 'plotly_dark')
fig


Вот что получится в результате:



А если вызвать другой:

fig.layout.update( template = 'gridon')
fig


То будет вот так:


Таким образом можно регулировать стили отображения графиков.
Более полный список шаблонов можно посмотреть тут Theming and templates in Python

28 July 2020

Plotly : подписи у графика и осей

Рассмотрим теперь как подписать оси и график.
Для начала выведем простой график:

fig = go.Figure()
trc2 = go.Scatter(
    x = x, y = y,
    name = 'Scatter sample',
    line = dict(color= 'green', dash='dot'),
    marker_symbol ='diamond-open',
    mode ='markers+lines'
)
fig.add_trace ( trc2 )


В результате получится зеленый пунктирный график с алмазами в качестве маркеров.
А теперь посмотрим что из себя представляет объект холста:

print(fig)

Поскольку если мы просто напишем fig то Юпитер просто выведет еще раз график. Значит надо воспользоваться оператором print.
Вот что у нас получится:


Как можно видеть в словаре для холста есть два основных ключа: data и layout. Т.е. данные и оформление. В данных мы можем видеть все свойства заданной точечной диграммы в том числе и данные по осям Х и Y.
А вот второй ключ для оформления - layout - что-то только  говорит о шаблоне но не более.
Если его тоже вывести вот так:

print(fig.layout.template) 

То получим огромный список форматирования. В том числе будет в конце и такое:



И это примерно то, что нам нужно.
Задать подписи в plotly можно вот так - т.е. обращаясь по словарю:

# подписать ось X - можно через обращение по ключу
fig['layout']['xaxis'].update( title = 'My X axis' )

# подписать ось Y - можно и без скобок
fig.layout.yaxis.update( title = 'My Y axis' )

# подписать весь график
fig['layout'].update( title = 'My Chart' )


Т.е. мы выбираем элемент - от холста идет оформление и далее нужная ось или целиком оформление. Далее к ней применяется метод update который и обнавляет значение по ключу title.
Вот что теперь в оформлении:


А вот как стал выглядеть график:


Аналогичных подписей можно добиться и адресными методами:

fig.update_xaxes( title = 'My new X axis' )
fig.update_yaxes( title = 'My new Y axis' )
fig.update_layout( title = 'My New Chart' )


Что даст следующее:


В результате мы подпишем и сам график и оси.

26 July 2020

Plotly: маркеры, линии и легенды

Продолжим играться с Plotly. Теперь посмотрим как можно поменять стиль линий и маркеров.
Управляет стилием отображения ключ словаря mode. Три основных варианта такие:
- markers  - чисто маркеры
- lines  - чисто линии
- markers+lines - маркеры + линии

Рассмотрим на примере, сначала отобразим чисто маркеры:

trc1 = dict( x = x, y = y )
trc1['name'] = 'Model data'
trc1['type'] = 'scatter' ; trc1['mode']='markers' # чисто маркеры
fig.add_trace ( trc1 )


Вот что у нас получится:


Как можно видеть, мы видим только маркеры. График только один и легенда не отображается.
Однако ничего не мешает и ее отобразить:

fig.update_layout(showlegend=True)


Этот вызов сформирует еще один график и уже с легендой:


Теперь попробуем поиграть с маркерами и для этого зададим режим "линия+маркеры" и сделаем линию черной.
Атрибут для линии - line - представляется в виде словаря, поэтому атрибут color уазазывается уже в нем.
Также изменим легенду:

trc1['mode']='markers+lines'
trc1['line'] =dict(color= 'black') 

trc1['name'] = 'Black lines + markers data'
fig.add_trace ( trc1 )


Во что будет после выполнения:


Как можно видеть, новый график перетер старый, однако это совершенно не страшно - панель легенды интерактивная. Т.е. можно выделить нужные нам графики. Например, вот я выделяю предыдущие данные - Model Data - и пропускаю черный график ( при этом он будет подписан более светлым шрифтом, что означает, что он не выделен ):


Т.е. в случае Plotly можно также идти последовательно добавляя все новые диаграммы, и просто выделять именно их при отображении. Чтобы не запутаться, имеет смысл менять при этом легенду.

Следующим шагом поиграемся с видом маркера. Для изменения вида маркера используется ключ marker_symbol, значение diamond-open означает алмаз без заливки. Для изменения цвета, размеров и толщины применяется ключ marker который задается опять словарем в котором цвет идет по ключу color, размер по ключу size, а вот толщину линии надо опять задавать через словарь

trc1['marker_symbol'] ='diamond-open' 
trc1['name'] = 'Diamond markers data'
trc1['marker'] = dict( line= dict(width= 1), color= 'red', size= 8)
fig.add_trace ( trc1 )


Вот что получается после этого выполнения:


Как можно видеть маркеры теперь стали в виде красных алмазов.

Далее поиграемся со стилем линии, пусть теперь мы будем без маркеров и с пунктирной синей линией.
Стиль линии определяется ключом line который имеет тип словаря:

trc1['line'] = dict(color= 'blue', dash='dot')
trc1['name'] = 'Blue dash lines data'
trc1['mode'] = 'lines'
fig.add_trace ( trc1 )


Вот что получится:


Ровно тоже самое можно сделать и при создании посредством использования не словаря, а через go.Scatter:

trc2 = go.Scatter( x = x, y = y, name = 'Scatter sample' )
trc2['line'] =dict(color= 'green', dash='dot')
trc2['marker_symbol']='diamond-open'
trc2['mode']='markers+lines'
fig.add_trace ( trc2 )


Вот результат:


Как можно видеть, цвет линии используется и маркерами, если не задавать их персонально.

24 July 2020

Plotly, еще о диаграммах: типы и рестарт ядра

Ранее в посте Plotly: о точечных диаграммах я забыл добавить еще один важный параметр при задании диаграммы посредством словаря: тип.
Как было видно, по умолчанию Plotly воспринял ее как точечную диаграмму.
Но если сделать вот так:

trc2['type'] = 'bar'

То диаграмма уже превратится в столбцовую или гистограмму:


И вот тут следует оговориться еще об одной важной функции у Блокнота Юпитера - перезапуску ядра или Kernel Restart. Все дело в том, что блокнотом удобно пользоваться последовательно находя решения, но в случае графики несколько последовательных вызовов могут налагаться друг на друга и поэтому графики будут смешиватся.
Вот живой пример -  в одном блокноте я тренировался для двух постов, поэтому у меня код идет последовательно:


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


Блокнот отобразил первый график и стал не следующую ячейку.
Теперь запускаем ее:


Блокнот еще раз отобразил тот же самый график, поскольку по факту мы добавляем такой же точечный график. Но самое интересное будет с добавлением при помощи словаря:


Как можно видеть: на новом графике столбцы добавились к предыдущему графику и сбоку справа появилась легенда.
Если поставить тип не bar, а scatter - будет тоже самое:


Т.е. второй график добавился к первому - это видно по легенде. А поскольку данные идентичные, то просто лег поверх со своим новым ( красным ) цветом.
Простой способ этого избежать такой:
- сделать перезапуск ядра с очисткой вывода:


- запустить ячейки, пропуская те, что не нужны:


Как можно видеть, я пропустил ячейки, выделенные красным. И поэтому когда я запускаю текущую ячейку с добавлением trc2 то добавляется только один график:


Именно таким же способом и получена гистограмма в начале поста.