在使用roassal3中使用多个图时,如何在线路末端添加水平线标签

发布于 2025-02-05 05:59:00 字数 2109 浏览 2 评论 0原文

我正在尝试使用Pharo 10中的Roassal3可视化多个系列数据。我设法绘制了图表的良好,但想标记线条。我尝试使用rslegend显示带有相应的颜色框(对应于线条颜色)的文本,但它们太大了,最终会缩小图形以适合画布。如果我可以操纵传说以不同的方式显示,那会有所帮助,但是我记得看到一个示例,使用较早版本的roassal,该版本在行末尾显示了每行的标签。这将是理想的,因此我尝试添加一个Rslabel作为情节的标志。这起作用了,除了标签都以各种角度出现(大概是绘图线的角度)。如何使最终标记标签水平显示?关于Roassal3的文档仍在进行中,因此我找不到任何示例。

我已经更新了示例代码,以显示我尝试使用的最终标记,传奇和装饰器(没有一个理想,但我也许可以与Decorator合作):

| chart plot dates values firstDate labels legend offset plotLabel renderedLabel canvasCopy |
chart := RSChart new.
canvasCopy := chart canvas copy.
dates := (20 to: 1 by: -1) collect: [ :i | Date today subtractDays: i ]. 
firstDate := dates first.
offset := 20 @ -50.
values := #(
    #(4.29 4.01 3.82 3.91 4.01 3.73 4.47 4.28 4.18 4.00 3.72 4.27 3.99 4.91 5.09 4.91 5.09 4.91 4.44 4.91)
    #(2.0 1.98 1.98 1.98 1.99 1.96 2.07 1.96 1.90 1.95 1.98 2.04 2.12 2.12 2.21 2.27 2.27 2.10 2.19 1.95)
    ).
labels := #('series 1' 'series 2').
values with: labels do: [ :series :label | 
   plot := RSLinePlot new markerEnd: (RSLabel new text: label).
   plot 
       x: (dates collect: [ :date | date julianDayNumber - firstDate julianDayNumber ])
       y: series.
   chart addPlot: plot.
    plotLabel := RSYLabelDecoration new right; 
        title: '~' , label;
        fontSize: 12;
        rotationAngle: 90;
        color: (chart colorFor: plot);
        offset: offset;
        yourself.
    chart addDecoration: plotLabel.
    renderedLabel := (plotLabel copy renderIn: canvasCopy) label.
    offset := (0 - renderedLabel textWidth) @ (offset y + renderedLabel textHeight + 4). 
 ].
canvasCopy shapes copy do: [ :shape | canvasCopy removeShape: shape ].
chart addDecoration: (RSHorizontalTick new labelConversion: [ :value | 
    Date julianDayNumber: firstDate julianDayNumber + value ]; useDiagonalLabel; yourself).
chart addDecoration: RSVerticalTick new.
chart ylabel: 'The values'.
chart build.
legend := RSLegend new.
legend container: chart canvas.
labels with: chart plots do: [ :c : p |
    legend text: c withBoxColor: (chart colorFor: p) ].
legend layout horizontalCompactTree .
legend build.
^chart canvas open

I'm trying to use Roassal3, in Pharo 10, to visualise multiple series of data. I've managed to draw the chart fine but want to label the lines. I tried using RSLegend to display the text with corresponding colour boxes (corresponding to the line colours) but they come out far too large and end up shrinking the graph to fit the canvas. If I could manipulate the legends to display differently, that would help, but I recall seeing an example, using an earlier version of Roassal, which displays a label for each line, at the end of the line. This would be ideal, so I tried adding an RSLabel as the markerEnd for the plot. This worked except that the labels all came out at various angles (presumably the angle of the plot lines, at the end). How can I get the end marker labels to display horizontally? Documentation on Roassal3 is still a work in progress, so I can't find any examples.

I've updated the sample code to show what I've tried with end markers, legends and decorators (none are ideal but I may be able to work with decorators):

| chart plot dates values firstDate labels legend offset plotLabel renderedLabel canvasCopy |
chart := RSChart new.
canvasCopy := chart canvas copy.
dates := (20 to: 1 by: -1) collect: [ :i | Date today subtractDays: i ]. 
firstDate := dates first.
offset := 20 @ -50.
values := #(
    #(4.29 4.01 3.82 3.91 4.01 3.73 4.47 4.28 4.18 4.00 3.72 4.27 3.99 4.91 5.09 4.91 5.09 4.91 4.44 4.91)
    #(2.0 1.98 1.98 1.98 1.99 1.96 2.07 1.96 1.90 1.95 1.98 2.04 2.12 2.12 2.21 2.27 2.27 2.10 2.19 1.95)
    ).
labels := #('series 1' 'series 2').
values with: labels do: [ :series :label | 
   plot := RSLinePlot new markerEnd: (RSLabel new text: label).
   plot 
       x: (dates collect: [ :date | date julianDayNumber - firstDate julianDayNumber ])
       y: series.
   chart addPlot: plot.
    plotLabel := RSYLabelDecoration new right; 
        title: '~' , label;
        fontSize: 12;
        rotationAngle: 90;
        color: (chart colorFor: plot);
        offset: offset;
        yourself.
    chart addDecoration: plotLabel.
    renderedLabel := (plotLabel copy renderIn: canvasCopy) label.
    offset := (0 - renderedLabel textWidth) @ (offset y + renderedLabel textHeight + 4). 
 ].
canvasCopy shapes copy do: [ :shape | canvasCopy removeShape: shape ].
chart addDecoration: (RSHorizontalTick new labelConversion: [ :value | 
    Date julianDayNumber: firstDate julianDayNumber + value ]; useDiagonalLabel; yourself).
chart addDecoration: RSVerticalTick new.
chart ylabel: 'The values'.
chart build.
legend := RSLegend new.
legend container: chart canvas.
labels with: chart plots do: [ :c : p |
    legend text: c withBoxColor: (chart colorFor: p) ].
legend layout horizontalCompactTree .
legend build.
^chart canvas open

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

十年不长 2025-02-12 05:59:00

在Alexandre Bergel的提示之后,我现在有一种合理的方法在情节线的末尾绘制标签。为了兴趣,我在下面的操场代码中包括了三种方法,使用绘图标签的结尾,使用右侧装饰并使用更标准的传说来识别情节线。这是凌乱的,在某些地方可以通过将代码移至更合适的对象来清理很多。

| chart plot dates values firstDate labels legend offset plotLabel renderedLabel canvasCopy maxOffset |
chart := RSChart new.
canvasCopy := RSCanvas new.
dates := (10 to: 1 by: -1) collect: [ :i | Date today subtractDays: i ]. 
firstDate := dates first.
offset := 20 @ -50.
maxOffset := 0.
values := #(
    #(3.72 4.27 3.99 4.91 5.09 4.91 5.09 4.91 4.44 4.91)
    #(4.29 4.01 3.82 3.91 4.01 3.73 4.47 4.28 4.18 4.00)
    #(1.98 2.04 2.12 2.12 2.21 2.27 2.27 2.10 2.19 1.95)
    #(2.5 2.3 2.7 2.73 2.15 2.6 2.63 2.57 2.4 2.8)
    #(2.0 1.98 1.98 1.98 1.99 1.96 2.07 1.96 1.90 1.95)
    ).
labels := #('first series' 'second series' 'series number 4' 'the third series' 'a fifth series').
values with: labels do: [ :series :label | 
   plot := RSLinePlot new.
   plot 
       x: (dates collect: [ :date | date julianDayNumber - firstDate julianDayNumber ])
       y: series.
   chart addPlot: plot.
    "If adding a legend to the right, RSYLabel decoration is needed but with modified offsets to get them to lay out vertically."
    plotLabel := RSYLabelDecoration new right; 
        title: '~' , label;
        fontSize: 12;
        rotationAngle: 90;
        color: (chart colorFor: plot);
        offset: offset;
        yourself.
    chart addDecoration: plotLabel.
    renderedLabel := (plotLabel renderIn: canvasCopy) label.
    maxOffset := maxOffset max: renderedLabel textWidth.
    offset := (0 - maxOffset) @ (offset y + renderedLabel textHeight + 4).
 ].
canvasCopy := nil.
chart addDecoration: (RSHorizontalTick new labelConversion: [ :value | 
    Date julianDayNumber: firstDate julianDayNumber + value ]; useDiagonalLabel; yourself).
chart addDecoration: RSVerticalTick new.
"When adding labels at the end of the plot lines, the right hand line of the chart box will overlay the labels so alter the
spine to a polygon which only draws the x and y axes. "
spine := chart decorations
        detect: [ :d | d class == RSChartSpineDecoration ].
spine shape: (RSPolygon new points: {(0 @ 0). (0 @ 0). (0 @ (chart extent y)). (chart extent x @ (chart extent y)). (chart extent x @ (chart extent y)). (0 @ (chart extent y)) }; noPaint; withBorder; yourself).
chart ylabel: 'The values'.
chart build.
"To use standard legend under the chart"
legend := RSLegend new defaultLabel: (RSLabel new fontSize: 8; yourself).
legend container: chart canvas.
labels with: chart plots do: [ :c : p |
    legend text: c withShape: (RSPolygon new points: { 0 @ -2. 10 @ -2. 10 @ 2. 0 @ 2 }; color: (chart colorFor: p))
    ].
legend layout grid.
legend build.

rsLabels := Dictionary new: chart plots size.
chart plots with: labels do: [ :plot :label | rsLabels at: plot put: ((RSLabel text: label) fontSize: 5) ].
lastys := chart plots collect: [ :pl | 
    Association key: pl value: (pl yScale scale: pl yValues last) ].
lastys sort: [ :el1 :el2 | 
    el1 value = el2 value 
        "If the last y coordinate is the same for both plots, order by the second last y point (reverse ordering)"
        ifTrue: [ (el1 key yValues at: el1 key yValues size - 1) > (el2 key yValues at: el2 key yValues size - 1) ] 
        ifFalse: [ el1 value < el2 value ] ].
lastys withIndexDo: [ :lasty :index |
        numPlots := lastys size.
        plot := lasty key.
        label := rsLabels at: plot.
        label color: plot color.
        chart canvas add: label.
        yPoint := lasty value.
        textHeight := label textHeight.
        index < numPlots ifTrue: [ 
            "Reset the y point to be about textHeight away from the next one, if they are close"
            (diff := (yPoint - (lastys at: index + 1) value) abs) < textHeight 
                ifTrue: [ yPoint := yPoint - (textHeight / 2) + (diff / 2) ] ].
        index > 1 ifTrue: [ 
            "Reset the y point to be about textHeight away from the last one, if they are close"
            (diff := ((lastys at: index - 1) value - yPoint ) abs) < textHeight 
                ifTrue: [ yPoint := yPoint + (textHeight / 2) - (diff / 2) ] ].
        label translateTo: ((plot xScale scale: plot xValues last) + (label textWidth / 2) + 1) @ yPoint.
    ].
^chart canvas

Following a tip from Alexandre Bergel, I now have a reasonable way to draw labels at the end of plot lines. For interest, I've included, in the playground code below, three ways to identify the plot lines, using the end of plot labels, using right side decorations and using a more standard legend. It's messy, in places but can be cleaned up a lot by moving code to more appropriate objects.

| chart plot dates values firstDate labels legend offset plotLabel renderedLabel canvasCopy maxOffset |
chart := RSChart new.
canvasCopy := RSCanvas new.
dates := (10 to: 1 by: -1) collect: [ :i | Date today subtractDays: i ]. 
firstDate := dates first.
offset := 20 @ -50.
maxOffset := 0.
values := #(
    #(3.72 4.27 3.99 4.91 5.09 4.91 5.09 4.91 4.44 4.91)
    #(4.29 4.01 3.82 3.91 4.01 3.73 4.47 4.28 4.18 4.00)
    #(1.98 2.04 2.12 2.12 2.21 2.27 2.27 2.10 2.19 1.95)
    #(2.5 2.3 2.7 2.73 2.15 2.6 2.63 2.57 2.4 2.8)
    #(2.0 1.98 1.98 1.98 1.99 1.96 2.07 1.96 1.90 1.95)
    ).
labels := #('first series' 'second series' 'series number 4' 'the third series' 'a fifth series').
values with: labels do: [ :series :label | 
   plot := RSLinePlot new.
   plot 
       x: (dates collect: [ :date | date julianDayNumber - firstDate julianDayNumber ])
       y: series.
   chart addPlot: plot.
    "If adding a legend to the right, RSYLabel decoration is needed but with modified offsets to get them to lay out vertically."
    plotLabel := RSYLabelDecoration new right; 
        title: '~' , label;
        fontSize: 12;
        rotationAngle: 90;
        color: (chart colorFor: plot);
        offset: offset;
        yourself.
    chart addDecoration: plotLabel.
    renderedLabel := (plotLabel renderIn: canvasCopy) label.
    maxOffset := maxOffset max: renderedLabel textWidth.
    offset := (0 - maxOffset) @ (offset y + renderedLabel textHeight + 4).
 ].
canvasCopy := nil.
chart addDecoration: (RSHorizontalTick new labelConversion: [ :value | 
    Date julianDayNumber: firstDate julianDayNumber + value ]; useDiagonalLabel; yourself).
chart addDecoration: RSVerticalTick new.
"When adding labels at the end of the plot lines, the right hand line of the chart box will overlay the labels so alter the
spine to a polygon which only draws the x and y axes. "
spine := chart decorations
        detect: [ :d | d class == RSChartSpineDecoration ].
spine shape: (RSPolygon new points: {(0 @ 0). (0 @ 0). (0 @ (chart extent y)). (chart extent x @ (chart extent y)). (chart extent x @ (chart extent y)). (0 @ (chart extent y)) }; noPaint; withBorder; yourself).
chart ylabel: 'The values'.
chart build.
"To use standard legend under the chart"
legend := RSLegend new defaultLabel: (RSLabel new fontSize: 8; yourself).
legend container: chart canvas.
labels with: chart plots do: [ :c : p |
    legend text: c withShape: (RSPolygon new points: { 0 @ -2. 10 @ -2. 10 @ 2. 0 @ 2 }; color: (chart colorFor: p))
    ].
legend layout grid.
legend build.

rsLabels := Dictionary new: chart plots size.
chart plots with: labels do: [ :plot :label | rsLabels at: plot put: ((RSLabel text: label) fontSize: 5) ].
lastys := chart plots collect: [ :pl | 
    Association key: pl value: (pl yScale scale: pl yValues last) ].
lastys sort: [ :el1 :el2 | 
    el1 value = el2 value 
        "If the last y coordinate is the same for both plots, order by the second last y point (reverse ordering)"
        ifTrue: [ (el1 key yValues at: el1 key yValues size - 1) > (el2 key yValues at: el2 key yValues size - 1) ] 
        ifFalse: [ el1 value < el2 value ] ].
lastys withIndexDo: [ :lasty :index |
        numPlots := lastys size.
        plot := lasty key.
        label := rsLabels at: plot.
        label color: plot color.
        chart canvas add: label.
        yPoint := lasty value.
        textHeight := label textHeight.
        index < numPlots ifTrue: [ 
            "Reset the y point to be about textHeight away from the next one, if they are close"
            (diff := (yPoint - (lastys at: index + 1) value) abs) < textHeight 
                ifTrue: [ yPoint := yPoint - (textHeight / 2) + (diff / 2) ] ].
        index > 1 ifTrue: [ 
            "Reset the y point to be about textHeight away from the last one, if they are close"
            (diff := ((lastys at: index - 1) value - yPoint ) abs) < textHeight 
                ifTrue: [ yPoint := yPoint + (textHeight / 2) - (diff / 2) ] ].
        label translateTo: ((plot xScale scale: plot xValues last) + (label textWidth / 2) + 1) @ yPoint.
    ].
^chart canvas
偏爱你一生 2025-02-12 05:59:00

我在Roassal3存储库中创建了一个问题。
亚历山大·伯格尔(Alexandre Bergel)的提示很好,但我认为这应该更简单。

例如这样


dates := (10 to: 1 by: -1) collect: [ :i | Date today subtractDays: i ]. 
values := #(
    #(3.72 4.27 3.99 4.91 5.09 4.91 5.09 4.91 4.44 4.91)
    #(4.29 4.01 3.82 3.91 4.01 3.73 4.47 4.28 4.18 4.00)
    #(1.98 2.04 2.12 2.12 2.21 2.27 2.27 2.10 2.19 1.95)
    #(2.5 2.3 2.7 2.73 2.15 2.6 2.63 2.57 2.4 2.8)
    #(2.0 1.98 1.98 1.98 1.99 1.96 2.07 1.96 1.90 1.95)
    ).

labels := #('first series' 'second series' 'series number 4' 'the third series' 'a fifth series').
chart := (values with: labels collect: [ :series :label | 
   plot := RSLinePlot new.
    plot label: '~' , label.
   plot 
       x: dates
       y: series.
   
 ]) asCombinePlot.
chart withLineSpineAxis. 
chart ylabel: 'The values'.
chart legend layout grid.
chart

I have created an issue in roassal3 repository.
The tip from Alexandre Bergel its good but I think and It should be simpler.

For example like this


dates := (10 to: 1 by: -1) collect: [ :i | Date today subtractDays: i ]. 
values := #(
    #(3.72 4.27 3.99 4.91 5.09 4.91 5.09 4.91 4.44 4.91)
    #(4.29 4.01 3.82 3.91 4.01 3.73 4.47 4.28 4.18 4.00)
    #(1.98 2.04 2.12 2.12 2.21 2.27 2.27 2.10 2.19 1.95)
    #(2.5 2.3 2.7 2.73 2.15 2.6 2.63 2.57 2.4 2.8)
    #(2.0 1.98 1.98 1.98 1.99 1.96 2.07 1.96 1.90 1.95)
    ).

labels := #('first series' 'second series' 'series number 4' 'the third series' 'a fifth series').
chart := (values with: labels collect: [ :series :label | 
   plot := RSLinePlot new.
    plot label: '~' , label.
   plot 
       x: dates
       y: series.
   
 ]) asCombinePlot.
chart withLineSpineAxis. 
chart ylabel: 'The values'.
chart legend layout grid.
chart

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文