88"""
99
1010import asciichartpy
11+ import numpy as np
1112
1213from easydiffraction .display .plotters .base import DEFAULT_HEIGHT
1314from easydiffraction .display .plotters .base import SERIES_CONFIG
@@ -43,7 +44,7 @@ def _get_legend_item(self, label):
4344 item = f'{ color_start } { line } { color_end } { name } '
4445 return item
4546
46- def plot (
47+ def plot_pattern (
4748 self ,
4849 x ,
4950 y_series ,
@@ -52,7 +53,10 @@ def plot(
5253 title ,
5354 height = None ,
5455 ):
55- """Render a compact ASCII chart in the terminal.
56+ """Render a compact ASCII line chart in the terminal.
57+
58+ Suitable for powder diffraction data where intensity is plotted
59+ against an x-axis variable (2θ, TOF, d-spacing).
5660
5761 Args:
5862 x: 1D array-like of x values (only used for range
@@ -84,3 +88,74 @@ def plot(
8488 padded = '\n ' .join (' ' + line for line in chart .splitlines ())
8589
8690 print (padded )
91+
92+ def plot_scatter_comparison (
93+ self ,
94+ x_calc ,
95+ y_meas ,
96+ y_meas_su ,
97+ axes_labels ,
98+ title ,
99+ height = None ,
100+ ):
101+ """Render a scatter comparison plot in the terminal.
102+
103+ Creates an ASCII scatter plot showing measured vs calculated
104+ values with a diagonal reference line.
105+
106+ Args:
107+ x_calc: 1D array-like of calculated values (x-axis).
108+ y_meas: 1D array-like of measured values (y-axis).
109+ y_meas_su: 1D array-like of measurement uncertainties
110+ (ignored in ASCII mode).
111+ axes_labels: Pair of strings for the x and y titles.
112+ title: Figure title.
113+ height: Number of text rows for the chart (default: 15).
114+ """
115+ # Intentionally unused; ASCII scatter doesn't show error bars
116+ del y_meas_su
117+
118+ if height is None :
119+ height = DEFAULT_HEIGHT
120+ width = 60 # TODO: Make width configurable
121+
122+ # Determine axis limits
123+ vmin = float (min (np .min (y_meas ), np .min (x_calc )))
124+ vmax = float (max (np .max (y_meas ), np .max (x_calc )))
125+ pad = 0.05 * (vmax - vmin ) if vmax > vmin else 1.0
126+ vmin -= pad
127+ vmax += pad
128+
129+ # Create empty grid
130+ grid = [[' ' for _ in range (width )] for _ in range (height )]
131+
132+ # Draw diagonal line (calc == meas)
133+ for i in range (min (width , height )):
134+ row = height - 1 - int (i * height / width )
135+ col = i
136+ if 0 <= row < height and 0 <= col < width :
137+ grid [row ][col ] = '·'
138+
139+ # Plot data points
140+ for xv , yv in zip (x_calc , y_meas , strict = False ):
141+ col = int ((xv - vmin ) / (vmax - vmin ) * (width - 1 ))
142+ row = height - 1 - int ((yv - vmin ) / (vmax - vmin ) * (height - 1 ))
143+ if 0 <= row < height and 0 <= col < width :
144+ grid [row ][col ] = '●'
145+
146+ # Build chart string with axes
147+ chart_lines = []
148+ for row in grid :
149+ label = '│'
150+ chart_lines .append (label + '' .join (row ))
151+
152+ # X-axis
153+ x_axis = '└' + '─' * width
154+
155+ # Print output
156+ console .paragraph (f'{ title } ' )
157+ console .print (f'{ axes_labels [1 ]} ' )
158+ for line in chart_lines :
159+ print (f' { line } ' )
160+ print (f' { x_axis } ' )
161+ console .print (f'{ " " * (width - 3 )} { axes_labels [0 ]} ' )
0 commit comments