Этот вопрос касается того, как выполнять условное форматирование в Plotly.
Экземпляры, где это может понадобиться:
Здесь я спрошу конкретно о гистограммах.
Возьмем следующие данные:
data = np.random.normal(size=1000)
Я хочу иметь гистограмму, в которой значения выше 0 помещаются в другой цвет.
Простое решение -
hist1 = go.Histogram(x=data[data<0],
opacity=0.75,
histnorm='density',
showlegend=False,
)
hist2 = go.Histogram(x=data[data>=0],
opacity=0.75,
histnorm='density',
showlegend=False,
)
layout = go.Layout(barmode='overlay')
fig = go.Figure(data=[hist1, hist2], layout=layout)
iplot(fig, show_link=False)
У этого решения есть несколько проблем:
histnorm = 'probability density'
, полученные графики «нормализуют» каждую из отдельных гистограмм, поэтому они будут выглядеть непропорционально.Есть лучший способ это сделать?
ОБНОВИТЬ
Хорошо, я могу решить (1) и (3) с помощью xbins
:
hist1 = go.Histogram(x=data[data>=0],
opacity=0.75,
xbins=dict(
start=0,
end=4,
size=0.12),
histnorm='density',
showlegend=False,
)
hist2 = go.Histogram(x=data[data<0],
opacity=0.75,
xbins=dict(
start=-0.12*33,
end=0,
size=0.12),
histnorm='density',
showlegend=False,
)
layout = go.Layout(barmode='overlay')
fig = go.Figure(data=[hist1, hist2], layout=layout)
iplot(fig, show_link=False)
Но как мне решить вторую проблему?
Для...
If I want to have histnorm = 'probability density' the resulting plots "normalize" each of the separate histograms, so they will look disproportionate.
... часть кажется, что вам придется нормализовать всю выборку, прежде чем разбивать ее на две разные гистограммы. Это означает, что вы делаете должен, чтобы создать диаграмма с областями с несколькими цветами под одной кривой. Но предлагаемое решение этой проблемы, к сожалению, похоже, состоит в том, чтобы назначить разные цвета двум трассам с помощью ...
df_pos = df.where(df < 0, 0)
df_neg = df.where(df > 0, 0)
... что, конечно же, возвращает вас туда, где вы находитесь.
Итак, чтобы получить то, что вы хотите, кажется, вам придется освободиться от границ gi.Histogram
, сначала разобраться с биннингом и нормализацией, а затем использовать комбинацию диаграмм с областями или гистограммы. Насколько я понимаю, это позаботится обо всех трех пунктах. Вот предложение, как это сделать:
Сюжет:
Код:
# imports
import plotly.graph_objects as go
from plotly.offline import iplot
import pandas as pd
import numpy as np
# theme
import plotly.io as pio
#pio.templates
#pio.templates.default = "plotly_white"
pio.templates.default = "none"
# Some sample data
np.random.seed(123)
x = np.random.normal(0, 1, 1000)
# numpy binning
binned = np.histogram(x, bins=30, density=True)
# retain some info abou the binning
yvals=binned[0]
x_last = binned[1][-1]
xvals=binned[1][:-1]
# organize binned data in a pandas dataframe
df_bin=pd.DataFrame(dict(x=xvals, y=yvals))
df_bin_neg = df.where(df['x'] < 0)
df_bin_pos = df.where(df['x'] > 0)
# set up plotly figure
fig=go.Figure()
# neagtive x
fig.add_trace(go.Scatter(
x=df_bin_neg['x'],
y=df_bin_neg['y'],
name = "negative X",
hoverinfo='all',
fill='tozerox',
#fillcolor='#ff7f0e',
fillcolor='rgba(255, 103, 0, 0.7)',
line=dict(color = 'rgba(0, 0, 0, 0)', shape='hvh')
))
# positive x
fig.add_trace(go.Scatter(
x=df_bin_pos['x'],
y=df_bin_pos['y'],
name = "positive X",
hoverinfo='all',
fill='tozerox',
#opacity=0.2,
#fillcolor='#ff7f0e',
#fillcolor='#1f77b4',
fillcolor='rgba(131, 149, 193, 0.9)',
line=dict(color = 'rgba(0, 0, 0, 0)', shape='hvh')
))
# adjust layout to insure max values are included
ymax = np.max([df_bin_neg['y'].max(), df_bin_neg['y'].max()])
fig.update_layout(yaxis=dict(range=[0,ymax+0.1]))
# adjust layout to match OPs original
fig.update_xaxes(showline=True, linewidth=1, linecolor='black', mirror=False, zeroline=False, showgrid=False)
fig.update_yaxes(showline=False)#, linewidth=2, linecolor='black', mirror=True)
fig.show()
Как мое предложение сработало для вас?