質問するログイン新規登録

Q&A

1回答

66閲覧

scottplot(V5,Winforms)で複数あるY軸の真上に軸ラベルを描きたい

k-kuma.esd

総合スコア21

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2026/01/30 02:08

編集2026/01/30 02:08

0

0

実現したいこと

タイトルの通りですが、通常はY軸の左右どちらかに出る軸ラベルを軸の真上に描きたい。

発生している問題・分からないこと

複数のY軸が存在している場合にその座標の取り方がわからない。
具体的な描画の仕方も。

該当のソースコード

特になし

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

生成AI(chatGPTやgemini)に訊いても、やたらと存在しないAPIを使ったり、変な位置に表示したり、何も表示できなかったりで解決できなかった。

どうも、Y軸の真上はY軸の担当描画エリア外らしく、工夫が必要らしい、というところまではわかりました。

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

guest

回答1

0

通常はY軸の左右どちらかに出る軸ラベルを軸の真上に描きたい。

ラベルを目盛りに重ねるって意味ですよね?見にくくないですか?(余計なお世話か^^;

Custom Axisを作れば、どうとでも描画できそうです。
ScottPlot5 WinForms Demo
ScottPlot5 WinForms Demo/Demos/CustomAxis.cs at main · ScottPlot/ScottPlot

ただ実際どうやるかは、既存実装を参考にしながら試行錯誤が必要そうです。
YAxisBase.cs at main · ScottPlot/ScottPlot
AxisBase.cs at main · ScottPlot/ScottPlot

FloatingAxisでよければリフレクションでごまかせましたが、残念ながら端に寄せるとはみ出た部分が消えますorz

cs

1using System.Reflection; 2using ScottPlot; 3using ScottPlot.AxisPanels; 4using ScottPlot.Plottables; 5using ScottPlot.WinForms; 6 7namespace Qa3g98l2vj841kv; 8 9public partial class Form1 : Form 10{ 11 public Form1() 12 { 13 InitializeComponent(); 14 15 var formsPlot1 = new FormsPlot { Dock = DockStyle.Fill, Parent = this, }; 16 17 // カスタムAxesに入れ替える 18 formsPlot1.Plot.Axes.Remove(formsPlot1.Plot.Axes.Left); 19 formsPlot1.Plot.Axes.AddLeftAxis(new CenterTickLabelYAxis(Edge.Left)); 20 21 var sig1 = formsPlot1.Plot.Add.Signal(Generate.Sin(mult: 0.01)); 22 sig1.Axes.YAxis = formsPlot1.Plot.Axes.Left; 23 formsPlot1.Plot.Axes.Left.Label.Text = "Left Axis"; 24 formsPlot1.Plot.Axes.Left.Label.ForeColor = sig1.Color; 25 26 27 formsPlot1.Plot.Axes.Remove(formsPlot1.Plot.Axes.Right); 28 formsPlot1.Plot.Axes.AddRightAxis(new CenterTickLabelYAxis(Edge.Right)); 29 30 var sig2 = formsPlot1.Plot.Add.Signal(Generate.Cos(mult: 100)); 31 sig2.Axes.YAxis = formsPlot1.Plot.Axes.Right; 32 formsPlot1.Plot.Axes.Right.Label.Text = "Right Axis"; 33 formsPlot1.Plot.Axes.Right.Label.ForeColor = sig2.Color; 34 35 36 // FloatingAxisでよければリフレクションでごまかせるが... 37 var floatingY = new FloatingAxis(formsPlot1.Plot.Axes.Left) 38 { 39 // 残念ながら端に寄せるとはみ出た部分が消えるorz 40 //Position = 0, 41 }; 42 formsPlot1.Plot.Add.Plottable(floatingY); 43 44 var labelStyle = (LabelStyle)floatingY.GetType() 45 .GetProperty("TickLabelStyle", BindingFlags.NonPublic | BindingFlags.Instance)! 46 .GetValue(floatingY)!; 47 labelStyle.Alignment = Alignment.MiddleCenter; 48 } 49} 50 51// カスタムAxes(Y軸専用) 52internal class CenterTickLabelYAxis : YAxisBase 53{ 54 public override Edge Edge { get; } 55 56 public CenterTickLabelYAxis(Edge edge) 57 { 58 if (edge != Edge.Left && edge != Edge.Right) throw new InvalidOperationException(); 59 60 Edge = edge; 61 TickGenerator = new ScottPlot.TickGenerators.NumericAutomatic(); 62 LabelRotation = edge == Edge.Left ? -90 : 90; 63 } 64 65 public override float Measure(Paint paint) 66 { 67 if (!IsVisible) return 0; 68 if (!Range.HasBeenSet) return SizeWhenNoData; 69 70 float maxTickLabelWidth = TickGenerator.Ticks.Length > 0 71 ? TickGenerator.Ticks.Select(x => TickLabelStyle.Measure(x.Label, paint).Width).Max() 72 : 0; 73 74 // 軸上にラベルを表示するのでPaddingBetweenTickAndAxisLabelsは不要 75 //float axisLabelHeight = string.IsNullOrEmpty(LabelStyle.Text) && LabelStyle.Image is null 76 // ? EmptyLabelPadding.Horizontal 77 // : LabelStyle.Measure(LabelText, paint).Height 78 // + PaddingBetweenTickAndAxisLabels.Horizontal 79 // + PaddingOutsideAxisLabels.Horizontal; 80 float axisLabelHeight = string.IsNullOrEmpty(LabelStyle.Text) && LabelStyle.Image is null 81 ? EmptyLabelPadding.Horizontal 82 : LabelStyle.Measure(LabelText, paint).Height 83 //+ PaddingBetweenTickAndAxisLabels.Horizontal 84 + PaddingOutsideAxisLabels.Horizontal; 85 86 // ラベルが軸の反対側に半分出るので1/2 87 //return maxTickLabelWidth + axisLabelHeight; 88 return maxTickLabelWidth / 2 + axisLabelHeight; 89 } 90 91 public override void Render(RenderPack rp, float size, float offset) 92 { 93 if (!IsVisible) return; 94 95 PixelRect panelRect = GetPanelRect(rp.DataRect, size, offset, rp.Paint); 96 float x = Edge == Edge.Left 97 ? panelRect.Left + PaddingOutsideAxisLabels.Horizontal 98 : panelRect.Right - PaddingOutsideAxisLabels.Horizontal; 99 Pixel labelPoint = new(x, rp.DataRect.VerticalCenter); 100 101 LabelAlignment = Alignment.UpperCenter; 102 LabelStyle.Render(rp.Canvas, labelPoint, rp.Paint); 103 104 //DrawTicks(rp, TickLabelStyle, panelRect, TickGenerator.Ticks, this, MajorTickStyle, MinorTickStyle); 105 DrawTicks2(rp, TickLabelStyle, panelRect, TickGenerator.Ticks, this, MajorTickStyle, MinorTickStyle); 106 107 DrawFrame(rp, panelRect, Edge, FrameLineStyle); 108 } 109 110 private static void DrawTicks2(RenderPack rp, LabelStyle label, PixelRect panelRect, IEnumerable<Tick> ticks, IAxis axis, TickMarkStyle majorStyle, TickMarkStyle minorStyle) 111 { 112 Paint paint = rp.Paint; 113 114 foreach (Tick tick in ticks) 115 { 116 paint.Color = tick.IsMajor ? majorStyle.Color : minorStyle.Color; 117 paint.StrokeWidth = tick.IsMajor ? majorStyle.Width : minorStyle.Width; 118 paint.IsAntialias = tick.IsMajor ? majorStyle.AntiAlias : minorStyle.AntiAlias; 119 float tickLength = tick.IsMajor ? majorStyle.Length : minorStyle.Length; 120 float yPx = axis.GetPixel(tick.Position, panelRect); 121 float x = axis.Edge == Edge.Left ? panelRect.Right : panelRect.Left; 122 //float xEdge = axis.Edge == Edge.Left ? x - tickLength : x + tickLength; 123 124 // 左右にtickLength分の線を引く 125 //PixelLine pxLine = new(x, yPx, xEdge, yPx); 126 PixelLine pxLine = new(x - tickLength, yPx, x + tickLength, yPx); 127 128 var lineStyle = tick.IsMajor ? majorStyle : minorStyle; 129 lineStyle.Render(rp.Canvas, paint, pxLine); 130 131 if (string.IsNullOrWhiteSpace(tick.Label) || !label.IsVisible) continue; 132 label.Text = tick.Label; 133 //float pxDistanceFromTick = 5; 134 //float pxDistanceFromEdge = tickLength + pxDistanceFromTick; 135 136 // 軸に重ねるので余計なオフセット計算なし 137 //float xPx = axis.Edge == Edge.Left ? x - pxDistanceFromEdge : x + pxDistanceFromEdge; 138 float xPx = x; 139 140 Pixel px = new(xPx, yPx); 141 if (label.Rotation == 0) 142 { 143 // 何も気にせずMiddleCenterに描く 144 //label.Alignment = axis.Edge == Edge.Left ? Alignment.MiddleRight : Alignment.MiddleLeft; 145 label.Alignment = Alignment.MiddleCenter; 146 } 147 label.Render(rp.Canvas, px, paint); 148 } 149 } 150}

アプリ画像

投稿2026/01/30 12:03

TN8001

総合スコア10225

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.29%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問