如何将图像设置为图表轴或沿图表轴设置?

2024-02-17

我正在尝试使用彩色光谱带作为图表的轴。这个想法是将图像上的颜色与其沿底部 x 轴相关的波长相匹配。条带需要更改大小以匹配图表区域的变化,并扩展和收缩部分以匹配图表区域中的滚动缩放。

我尝试过使用图像注释,但随着图表区域的变化,注释尺寸保持固定。此外,聚焦于鼠标位置的滚动缩放显然对注释没有影响。

最接近的方法是使用图像作为图表区域的背景。当图表区域发生变化时,这会自动缩放图像,但滚动缩放对背景图像没有影响。此外,背景最好清晰,以避免模糊数据绘图点。我可以编辑图像以使其具有较大的透明部分,并且底部只有一个彩色条带,但即使如此,该条带也可能会掩盖较低强度的数据点。

Spectrum as annotation and background: enter image description here

Annotation not scaling, background scales well: enter image description here

Both annotation and background not scaling with zooming: enter image description here


这是个好主意。

最简单的方法是将图像绘制在Paint图表中的事件,也许PrePaint.

让我们去工作吧..我们将使用DrawImage https://msdn.microsoft.com/en-us/library/ms142040(v=vs.110).aspx重载允许我们缩放和裁剪。为此我们需要两个矩形。

第一个挑战是始终获得正确的目标矩形。

为此我们需要将InnerPlotPosition从相对位置到绝对像素。

这两个功能将有助于:

RectangleF ChartAreaClientRectangle(Chart chart, ChartArea CA)
{
    RectangleF CAR = CA.Position.ToRectangleF();
    float pw = chart.ClientSize.Width / 100f;
    float ph = chart.ClientSize.Height / 100f;
    return new RectangleF(pw * CAR.X, ph * CAR.Y, pw * CAR.Width, ph * CAR.Height);
}

RectangleF InnerPlotPositionClientRectangle(Chart chart, ChartArea CA)
{
    RectangleF IPP = CA.InnerPlotPosition.ToRectangleF();
    RectangleF CArp = ChartAreaClientRectangle(chart, CA);

    float pw = CArp.Width / 100f;
    float ph = CArp.Height / 100f;

    return new RectangleF(CArp.X + pw * IPP.X, CArp.Y + ph * IPP.Y, 
                            pw * IPP.Width, ph * IPP.Height);
}

使用这些数字设置目标矩形就非常简单:

Rectangle tgtR = Rectangle.Round(new RectangleF(ipr.Left, ipr.Bottom - 15, ipr.Width, 15));

你可以选择你喜欢的高度..

下一个挑战是源矩形。

如果没有缩放,它就会简单地是:

Rectangle srcR = new Rectangle( 0, 0, bmp.Width, bmp.Height);

但对于缩放和平移,我们需要对其进行缩放;为此,我们可以使用 x 轴和ScaleView's Minimum and Maximum values.

我们计算轴上第一个和最后一个点的因子:

double f1 = ax.ScaleView.ViewMinimum / (ax.Maximum - ax.Minimum);
double f2 = ax.ScaleView.ViewMaximum / (ax.Maximum - ax.Minimum);

现在我们得到源矩形可能是这样的:

int x  = (int)(bmp.Width * f1);
int xx = (int)(bmp.Width * f2);
Rectangle srcR = new Rectangle( x, 0, xx - x, bmp.Height);

让我们把它放在一起:

private void chart_PrePaint(object sender, ChartPaintEventArgs e)
{
    // a few short names
    Graphics g = e.ChartGraphics.Graphics;  
    ChartArea ca = chart.ChartAreas[0];
    Axis ax = ca.AxisX;

    // pixels of plot area
    RectangleF ipr = InnerPlotPositionClientRectangle(chart, ca);

    // scaled first and last position
    double f1 = ax.ScaleView.ViewMinimum / (ax.Maximum - ax.Minimum);
    double f2 = ax.ScaleView.ViewMaximum / (ax.Maximum - ax.Minimum);

    // actual drawing with the zooming overload
    using (Bitmap bmp = (Bitmap)Bitmap.FromFile(imagePath))
    {
        int x  = (int)(bmp.Width * f1);
        int xx = (int)(bmp.Width * f2);
        Rectangle srcR = new Rectangle( x, 0, xx - x, bmp.Height);
        Rectangle tgtR = Rectangle.Round(
                         new RectangleF(ipr.Left , ipr.Bottom - 15, ipr.Width, 15));
        g.DrawImage(bmp, tgtR, srcR, GraphicsUnit.Pixel);
    }
}

一些注意事项:

  • 当然,我建议使用图像资源,而不是总是从磁盘加载!

  • 绘图将始终覆盖数据点和网格。你也可以..

  • 选择不同的最小值来腾出空间

  • 使图像变小

  • 将其移至 x 轴标签下方

  • 使图像半透明

  • 使 x 轴足够粗,以便可以容纳图像条:ax.LineWidth = 10

对于后一种解决方案,您需要根据缩放状态偏移 y 位置。又快又脏:int yoff = (ax.ScaleView.IsZoomed ? 12 : 5);。为了避免出现黑色条纹,还可以将轴设置为透明或 Chart.BackColor..

Update:

您还可以恢复使用StripLine。它可以扩展其BackgroundImage每当更改比例视图时(即缩放或平移时),您都必须创建合适的图像。为此,上述大部分代码将用于创建新图像。看这个帖子 https://stackoverflow.com/questions/49937962/combine-barchart-and-pointchart/49939521#49939521有关添加和替换不同的示例NamedImage到图表! (相关部分接近标记图像的结尾!)

事实上,我发现这种方式是最好的解决方案,并添加了第二个答案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将图像设置为图表轴或沿图表轴设置? 的相关文章

随机推荐