我有一个数据框,其中包含y1
来自不同文件的数据(由一列表示)。如果我使用 dataframe.hvplot() 绘制数据。我使用by
关键字为每个文件绘制单独的行。现在我想y2
在同一个图中绘制数据,但在辅助 y 轴上。根据这篇文章,我可以得到我想要的,但这似乎是一个非常丑陋且不可靠的解决方案。有没有更优雅的方法来实现这一点?
MWE:
import holoviews as hv
import pandas as pd
import hvplot.pandas
import numpy as np
from bokeh.models import Range1d, LinearAxis
N = 11
x = np.linspace(0,10,N)
def plot_secondary(plot, element):
fig: Figure = plot.state
glyph_first: GlyphRenderer = fig.renderers[0] # will be the original plot
glyph_last: GlyphRenderer = fig.renderers[-1] # will be the new plot
right_axis_name = "twiny"
y_first_min = np.nan
y_first_max = np.nan
y_first_name = glyph_first.glyph.y
y_last_min = np.nan
y_last_max = np.nan
y_last_name = glyph_last.glyph.y
# find overall min and max based on y name (assuming only two names exist)
for glyph in fig.renderers:
if glyph.glyph.y == y_first_name:
y_first_min = np.nanmin([y_first_min, glyph.data_source.data[y_first_name].min()])
y_first_max = np.nanmax([y_first_max, glyph.data_source.data[y_first_name].max()])
# Recreate primary axis (left)
y_first_offset = (y_first_max - y_first_min) * 0.1
fig.y_range = Range1d(
start=y_first_min - y_first_offset,
end=y_first_max + y_first_offset
)
fig.y_range.name = glyph.y_range_name
elif glyph.glyph.y == y_last_name:
y_last_min = np.nanmin([y_last_min, glyph.data_source.data[y_last_name].min()])
y_last_max = np.nanmax([y_last_max, glyph.data_source.data[y_last_name].max()])
# Create secondary axis (right)
y_last_offset = (y_last_max - y_last_min) * 0.1
fig.extra_y_ranges = {right_axis_name: Range1d(
start=y_last_min - y_last_offset,
end=y_last_max + y_last_offset
)}
fig.y_range.name = glyph.y_range_name
glyph.y_range_name = right_axis_name
else:
raise('Cannot handle more than two names for y data.')
fig.add_layout(LinearAxis(y_range_name=right_axis_name, axis_label=glyph_last.glyph.y), "right")
# create some dummy data
data1 = {
"x": x,
"y1": 2*x,
"y2": np.power(x,2),
"label": 'A'
}
data2 = {
"x": x,
"y1": -x,
"y2": -0.5*np.power(x,2),
"label": 'B'
}
df = pd.concat([pd.DataFrame(data1), pd.DataFrame(data2)])
color_cycle = hv.Cycle(['blue', 'red'])
p1=df.hvplot(x='x', y=['y1'], by=['label'], color=color_cycle, line_dash='solid')
p2=df.hvplot(x='x', y=['y2'], by=['label'], color=color_cycle, line_dash='dashed').options(hooks=[plot_secondary])
p1*p2