Plotly: как использовать смещение цветов для разных трасс?

#python #plotly #plotly-python

#python #plotly #plotly-python

Вопрос:

Я строю графики в plotly, используя данные из pandas. У меня есть словарь, где ключом является дата, например 2020-10-26 , а значением является a pd.Dataframe , в котором есть time столбец и 2 столбца данных.

Пример данных в формате .csv:

 datetime,SeriesA,SeriesB
2020-10-23 06:00:03.560996 01:00,0,0
2020-10-23 06:05:03.358855 01:00,0,0
2020-10-23 06:10:02.927629 01:00,0,0
2020-10-23 06:15:02.514076 01:00,0,0
2020-10-23 06:20:03.231765 01:00,0,0
2020-10-23 06:25:02.790677 01:00,0,0
2020-10-23 06:30:04.252621 01:00,0,0
2020-10-23 06:35:02.845816 01:00,0,0
2020-10-23 06:40:03.510711 01:00,0,0
2020-10-23 06:45:03.235390 01:00,0,0
2020-10-23 06:50:02.689276 01:00,0,0
2020-10-23 06:55:03.569083 01:00,0,0
2020-10-23 07:00:08.279973 01:00,0,0
2020-10-23 07:05:02.816612 01:00,0,0
2020-10-23 07:10:03.417112 01:00,2,0
2020-10-23 07:15:03.041706 01:00,2,0
2020-10-23 07:20:02.537567 01:00,3,0
2020-10-23 07:25:03.266320 01:00,5,0
2020-10-23 07:30:02.900625 01:00,5,0
2020-10-23 07:35:03.577497 01:00,5,0
2020-10-23 07:40:03.179229 01:00,7,0
2020-10-23 07:45:02.743349 01:00,10,0
2020-10-23 07:50:03.285283 01:00,11,0
2020-10-23 07:55:02.858642 01:00,11,0
2020-10-23 08:00:03.641784 01:00,10,0
2020-10-23 08:05:03.256219 01:00,10,0
2020-10-23 08:10:02.994154 01:00,9,0
2020-10-23 08:15:02.525091 01:00,9,0
2020-10-23 08:20:03.261529 01:00,9,0
2020-10-23 08:25:02.890515 01:00,9,0
2020-10-23 08:30:03.533912 01:00,9,0
2020-10-23 08:35:03.206510 01:00,7,0
2020-10-23 08:40:02.719998 01:00,7,0
2020-10-23 08:45:03.310976 01:00,7,0
2020-10-23 08:50:02.996382 01:00,4,0
2020-10-23 08:55:02.697139 01:00,7,0
2020-10-23 09:00:03.721763 01:00,7,0
2020-10-23 09:05:03.182091 01:00,7,0
2020-10-23 09:10:02.765971 01:00,8,0
2020-10-23 09:15:03.360654 01:00,8,0
2020-10-23 09:20:02.990297 01:00,10,0
2020-10-23 09:25:02.661501 01:00,11,0
2020-10-23 09:30:03.275004 01:00,14,0
2020-10-23 09:35:02.868574 01:00,14,0
2020-10-23 09:40:03.460406 01:00,15,0
2020-10-23 09:45:02.905538 01:00,18,0
2020-10-23 09:50:02.423377 01:00,20,0
2020-10-23 09:55:02.984470 01:00,24,0
2020-10-23 10:00:02.622322 01:00,24,0
2020-10-23 10:05:03.166971 01:00,26,0
2020-10-23 10:10:02.859788 01:00,27,0
2020-10-23 10:15:03.494884 01:00,27,0
2020-10-23 10:20:03.113251 01:00,28,0
2020-10-23 10:25:02.606379 01:00,29,0
2020-10-23 10:30:03.268436 01:00,30,0
2020-10-23 10:35:02.889803 01:00,35,0
2020-10-23 10:40:03.577297 01:00,37,0
2020-10-23 10:45:03.082449 01:00,37,0
2020-10-23 10:50:02.680122 01:00,37,0
2020-10-23 10:55:03.207217 01:00,40,0
2020-10-23 11:00:03.633144 01:00,40,0
2020-10-23 11:05:03.342871 01:00,39,0
2020-10-23 11:10:02.952711 01:00,40,0
2020-10-23 11:15:02.519122 01:00,42,0
2020-10-23 11:20:03.330055 01:00,42,0
2020-10-23 11:25:02.948754 01:00,44,0
2020-10-23 11:30:02.505908 01:00,43,0
2020-10-23 11:35:03.091022 01:00,42,0
2020-10-23 11:40:02.570567 01:00,38,0
2020-10-23 11:45:03.214173 01:00,38,0
2020-10-23 11:50:02.909830 01:00,38,0
2020-10-23 11:55:02.493098 01:00,40,4
2020-10-23 12:00:03.200475 01:00,41,5
2020-10-23 12:05:02.851384 01:00,45,6
2020-10-23 12:10:03.545193 01:00,45,7
2020-10-23 12:15:03.191269 01:00,42,8
2020-10-23 12:20:02.726863 01:00,45,9
2020-10-23 12:25:03.444214 01:00,47,9
2020-10-23 12:30:03.266972 01:00,49,9
2020-10-23 12:35:02.904323 01:00,53,9
2020-10-23 12:40:03.548200 01:00,53,10
2020-10-23 12:45:03.065578 01:00,49,10
2020-10-23 12:50:02.517495 01:00,49,10
2020-10-23 12:55:03.228082 01:00,48,10
2020-10-23 13:00:03.344813 01:00,53,12
2020-10-23 13:05:02.999236 01:00,54,12
2020-10-23 13:10:02.555469 01:00,54,14
2020-10-23 13:15:03.424480 01:00,62,14
2020-10-23 13:20:03.178713 01:00,62,14
2020-10-23 13:25:02.856786 01:00,64,14
2020-10-23 13:30:03.538784 01:00,66,17
2020-10-23 13:35:03.226000 01:00,65,17
2020-10-23 13:40:02.738893 01:00,65,20
2020-10-23 13:45:03.216859 01:00,68,20
2020-10-23 13:50:02.801997 01:00,71,22
2020-10-23 13:55:03.325790 01:00,73,22
2020-10-23 14:00:03.032139 01:00,76,24
2020-10-23 14:05:02.713786 01:00,77,23
2020-10-23 14:10:03.329970 01:00,84,23
2020-10-23 14:15:02.891348 01:00,81,23
2020-10-23 14:20:02.587012 01:00,84,23
2020-10-23 14:25:03.119747 01:00,82,25
2020-10-23 14:30:03.751337 01:00,82,25
2020-10-23 14:35:03.332507 01:00,88,23
2020-10-23 14:40:03.049341 01:00,85,23
2020-10-23 14:45:02.630885 01:00,85,20
2020-10-23 14:50:03.287446 01:00,86,19
2020-10-23 14:55:02.915400 01:00,86,18
2020-10-23 15:00:07.137616 01:00,85,16
2020-10-23 15:05:02.683116 01:00,82,14
2020-10-23 15:10:03.373464 01:00,85,14
2020-10-23 15:15:03.128489 01:00,88,14
2020-10-23 15:20:02.846043 01:00,86,14
2020-10-23 15:25:03.462925 01:00,87,15
2020-10-23 15:30:03.131532 01:00,92,15
2020-10-23 15:35:02.721796 01:00,97,15
2020-10-23 15:40:03.375007 01:00,102,15
2020-10-23 15:45:03.020813 01:00,101,15
2020-10-23 15:50:02.563966 01:00,91,15
2020-10-23 15:55:03.235962 01:00,89,15
2020-10-23 16:00:03.040490 01:00,87,19
2020-10-23 16:05:02.467856 01:00,90,19
2020-10-23 16:10:03.099486 01:00,92,19
2020-10-23 16:15:02.637764 01:00,94,18
2020-10-23 16:20:03.153888 01:00,94,18
2020-10-23 16:25:02.736936 01:00,91,18
2020-10-23 16:30:03.359875 01:00,93,17
2020-10-23 16:35:02.974661 01:00,90,19
2020-10-23 16:40:02.513056 01:00,91,19
2020-10-23 16:45:03.092756 01:00,92,20
2020-10-23 16:50:02.659552 01:00,96,21
2020-10-23 16:55:03.478308 01:00,96,21
2020-10-23 17:00:04.117017 01:00,91,24
2020-10-23 17:05:02.685190 01:00,95,24
2020-10-23 17:10:03.267694 01:00,96,24
2020-10-23 17:15:03.019771 01:00,101,26
2020-10-23 17:20:02.526978 01:00,105,31
2020-10-23 17:25:03.206001 01:00,106,33
2020-10-23 17:30:02.865237 01:00,106,35
2020-10-23 17:35:03.366034 01:00,107,40
2020-10-23 17:40:02.992485 01:00,114,42
2020-10-23 17:45:02.552713 01:00,108,44
2020-10-23 17:50:03.218854 01:00,116,43
2020-10-23 17:55:02.755765 01:00,112,45
2020-10-23 18:00:03.442851 01:00,112,46
2020-10-23 18:05:03.125732 01:00,113,43
2020-10-23 18:10:02.650996 01:00,113,42
2020-10-23 18:15:03.224235 01:00,115,42
2020-10-23 18:20:02.852754 01:00,114,44
2020-10-23 18:25:03.375879 01:00,110,45
2020-10-23 18:30:03.504858 01:00,110,42
2020-10-23 18:35:03.023102 01:00,107,40
2020-10-23 18:40:02.560902 01:00,103,37
2020-10-23 18:45:03.183863 01:00,101,37
2020-10-23 18:50:02.776229 01:00,102,40
2020-10-23 18:55:03.366546 01:00,99,40
2020-10-23 19:00:05.100330 01:00,94,40
2020-10-23 19:05:02.577656 01:00,93,41
2020-10-23 19:10:03.234291 01:00,93,45
2020-10-23 19:15:02.765871 01:00,89,45
2020-10-23 19:20:03.269868 01:00,92,45
2020-10-23 19:25:02.891858 01:00,89,43
2020-10-23 19:30:03.859379 01:00,86,43
2020-10-23 19:35:03.410564 01:00,89,42
2020-10-23 19:40:03.126319 01:00,85,39
2020-10-23 19:45:02.686578 01:00,82,38
2020-10-23 19:50:03.409481 01:00,80,34
2020-10-23 19:55:03.000850 01:00,78,34
2020-10-23 20:00:04.680330 01:00,81,32
2020-10-23 20:05:03.269432 01:00,81,32
2020-10-23 20:10:02.847406 01:00,83,33
2020-10-23 20:15:03.422214 01:00,79,34
2020-10-23 20:20:03.025468 01:00,78,33
2020-10-23 20:25:02.639656 01:00,75,31
2020-10-23 20:30:03.241510 01:00,71,31
2020-10-23 20:35:02.787490 01:00,66,31
2020-10-23 20:40:03.433893 01:00,65,28
2020-10-23 20:45:03.029779 01:00,67,20
2020-10-23 20:50:02.478445 01:00,63,19
2020-10-23 20:55:03.064874 01:00,63,19
2020-10-23 21:00:11.388007 01:00,59,16
2020-10-23 21:05:02.915554 01:00,59,16
2020-10-23 21:10:02.508213 01:00,54,16
2020-10-23 21:15:03.024323 01:00,53,16
2020-10-23 21:20:02.577168 01:00,51,16
2020-10-23 21:25:03.403608 01:00,50,13
2020-10-23 21:30:03.193242 01:00,47,13
2020-10-23 21:35:03.329020 01:00,47,10
2020-10-23 21:40:02.906741 01:00,45,10
2020-10-23 21:45:02.359574 01:00,38,10
2020-10-23 21:50:03.115074 01:00,37,10
2020-10-23 21:55:02.770450 01:00,34,10
2020-10-23 22:00:03.658104 01:00,34,10
2020-10-23 22:05:03.182939 01:00,34,10
2020-10-23 22:10:02.834897 01:00,34,10
2020-10-23 22:15:03.545781 01:00,33,10
2020-10-23 22:20:03.130197 01:00,31,10
2020-10-23 22:25:02.644800 01:00,31,10
2020-10-23 22:30:03.311895 01:00,30,10
2020-10-23 22:35:02.958333 01:00,30,10
2020-10-23 22:40:02.527824 01:00,30,9
2020-10-23 22:45:03.243267 01:00,29,9
2020-10-23 22:50:02.808424 01:00,25,9
2020-10-23 22:55:03.338346 01:00,24,9
  
 for day, df in data.items():
    day_name = datetime.datetime.strptime(day, "%Y-%m-%d").strftime("%A") # convert str to datetime, then to day
    traces.append(go.Scatter(x=df["time"], y=df["SeriesA"], name=f"{day_name} SeriesA"))
    traces.append(go.Scatter(x=df["time"], y=df["SeriesB"], name=f"{day_name} SeriesB"))
  

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

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

 # If statement for every day of the week
if day_name == "Monday":
    color = red_hex_values[monday_idx]
    monday_idx  = 1

traces.append(go.Scatter(x=df["time"], y=df["SeriesA"], name=f"{day_name} SeriesA", color=color))
  

Однако это кажется очень грязным способом сделать это.

Ответ №1:

Вступление

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

  1. Как создать пользовательскую цветовую шкалу
  2. Как использовать смещение цветов для будних дней в plotly.

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

Ответ

Это интересный вопрос, и я думаю, что нашел жизнеспособное решение с помощью циклической итерации указанных цветовых шкал, хранящихся в виде значений в словаре daymap , где ключами являются названия дней недели:

 daymap = {'Monday':cycle(px.colors.sequential.Reds),
           'Tuesday':cycle(px.colors.sequential.Greens),
         }
  

px.colors.sequential.Reds и px.colors.sequential.Greens встроенные цветовые шкалы plotly. Вы специально просили желтый. Но пока это придется сделать.

Я настроил его так, что любая определенная weekday, color scale пара, которую вы настроили, назначается на графике, а всем именам дней недели, которые вы решили не определять, присваивается один пользовательский цвет, указанный вами с помощью пользовательской функции colfx() :

 def colfx(daymap, day_name, default_color):
    if day_name in daymap.keys():
        return next(daymap[day_name])
    else:
        return default_color
  

Приведенный ниже полный фрагмент кода со случайной выборкой данных за 60 дней создаст график 1 ниже, используя, среди нескольких других деталей, спецификации, упомянутые выше.

График 1

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

График 2 создается путем добавления другого ключа, пары значений daymap и изменения цвета по умолчанию colfx() на 'rgba(150,150,150, 0.2)' . Я счел целесообразным использовать rgba цвета для цвета по умолчанию, поскольку последний термин 0.2 позволит вам легко установить непрозрачность цвета.

График 2

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

Полный код

 import pandas as pd
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
from itertools import cycle

# data
obs = 60
dates = pd.date_range(start='2020-01-01', periods=obs)
random = np.random.RandomState(0)
df = pd.DataFrame({'data': np.random.uniform(low=0, high=100, size=obs).tolist()}, index=dates)

# custom function to assign next color in a color sequence
# for each new day defined in the dict daymap
def colfx(daymap, day_name, default_color):
    if day_name in daymap.keys():
        return next(daymap[day_name])
    else:
        return default_color

# color specifications for weekday
daymap = {'Monday':cycle(px.colors.sequential.Reds),
           'Tuesday':cycle(px.colors.sequential.Greens),
           'Friday':cycle(px.colors.sequential.thermal)
         }
    
# container for weekday names added to the figure legend
# if the weekday names has ALREADY been added to the legend,
# then no further additions are made
fignames = []

fig=go.Figure()
for row in df.iterrows():
    day_name=row[0].strftime("%A")
    fignames = [d.name for d in fig.data]
    fig.add_bar(x=[row[0]],
                y=[row[1]['data']],
                marker_color=colfx(daymap=daymap, day_name = day_name, default_color='rgba(150,150,150, 0.2)'),
                name=day_name,
                legendgroup = day_name,
                showlegend = False if day_name in fignames else True
               )
    
fig.show()
  

Комментарии:

1. Спасибо, это отлично работает. Я также нашел from plotly.colors import n_colors , который позволяет вам устанавливать начальный и конечный цвета, а также количество цветов между ними, что очень удобно.