0

我有一个数据框,其中包含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

输出: 在此处输入图像描述

4

0 回答 0