Skip to content

Commit dab14b9

Browse files
authored
refactor: complete symlog tick generation implementation
Fixes #342 - Complete symlog tick generation implementation with proper exponential positioning and overlap handling
1 parent 5f6952c commit dab14b9

11 files changed

+346
-39
lines changed

.github/workflows/test-coverage.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ jobs:
6464
6565
- name: Build with coverage flags
6666
run: |
67-
make build ARGS="--flag '-fprofile-arcs -ftest-coverage'"
67+
make build ARGS="--flag '-fprofile-arcs -ftest-coverage -Wno-implicit-interface'"
6868
6969
- name: Build required examples for tests
7070
run: |
@@ -73,26 +73,26 @@ jobs:
7373
- name: Run FPM tests with coverage
7474
run: |
7575
mkdir -p /tmp/test
76-
timeout 15m make test-ci ARGS="--flag '-fprofile-arcs -ftest-coverage'" || echo "Some CI tests may have timed out"
76+
timeout 15m make test-ci ARGS="--flag '-fprofile-arcs -ftest-coverage -Wno-implicit-interface'" || echo "Some CI tests may have timed out"
7777
7878
- name: Run antialiasing quality tests with ImageMagick
7979
run: |
8080
# Verify ImageMagick is available
8181
if magick -version > /dev/null 2>&1; then
8282
echo "ImageMagick found - running graphics quality tests"
83-
fpm test test_antialiasing_restoration --flag '-fprofile-arcs -ftest-coverage'
84-
fpm test test_antialiasing_comprehensive --flag '-fprofile-arcs -ftest-coverage'
83+
fpm test test_antialiasing_restoration --flag '-fprofile-arcs -ftest-coverage -Wno-implicit-interface'
84+
fpm test test_antialiasing_comprehensive --flag '-fprofile-arcs -ftest-coverage -Wno-implicit-interface'
8585
else
8686
echo "ImageMagick not found - skipping graphics quality tests"
8787
fi
8888
8989
- name: Test FPM example build
9090
run: |
91-
make test ARGS="--target test_system_fpm_example"
91+
make test ARGS="--target test_system_fpm_example --flag '-fprofile-arcs -ftest-coverage -Wno-implicit-interface'"
9292
9393
- name: Test CMake example build
9494
run: |
95-
make test ARGS="--target test_system_cmake_example"
95+
make test ARGS="--target test_system_cmake_example --flag '-fprofile-arcs -ftest-coverage -Wno-implicit-interface'"
9696
9797
- name: Validate PNG output with PIL
9898
continue-on-error: true

.github/workflows/windows-ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ jobs:
6666
shell: cmd
6767
run: |
6868
set FORTPLOT_ENABLE_FFMPEG=1
69-
fpm build --flag "-fPIC"
69+
fpm build --flag "-cpp -fmax-stack-var-size=65536 -Wno-implicit-interface"
7070
7171
- name: Run Windows tests with built-in timeout protection
7272
shell: cmd
@@ -78,7 +78,7 @@ jobs:
7878
echo System command timeouts: 3 seconds
7979
echo Set FORTPLOT_DEBUG_TIMEOUT=1 for verbose logging
8080
echo ===============================================
81-
fpm test --flag "-cpp -fmax-stack-var-size=65536"
81+
fpm test --flag "-cpp -fmax-stack-var-size=65536 -Wno-implicit-interface"
8282
8383
- name: Run antialiasing quality tests with ImageMagick (optional on Windows)
8484
continue-on-error: true
@@ -88,5 +88,5 @@ jobs:
8888
magick -version
8989
echo.
9090
echo Running graphics quality tests (optional on Windows due to path issues)...
91-
fpm test test_antialiasing_restoration --flag "-cpp -fmax-stack-var-size=65536" || echo Test skipped due to ImageMagick detection issue on Windows
92-
fpm test test_antialiasing_comprehensive --flag "-cpp -fmax-stack-var-size=65536" || echo Test skipped due to ImageMagick detection issue on Windows
91+
fpm test test_antialiasing_restoration --flag "-cpp -fmax-stack-var-size=65536 -Wno-implicit-interface" || echo Test skipped due to ImageMagick detection issue on Windows
92+
fpm test test_antialiasing_comprehensive --flag "-cpp -fmax-stack-var-size=65536 -Wno-implicit-interface" || echo Test skipped due to ImageMagick detection issue on Windows

BACKLOG.md

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,32 @@
11
# Development Backlog
22

3-
## CURRENT SPRINT (Critical PNG/PDF Rendering Issues)
3+
## CURRENT SPRINT (Critical CI and Rendering Issues)
44

5-
**🚨 CRITICAL: User-visible PNG/PDF rendering completely broken**
6-
- [x] #338: Fix - No axes visible and plots strangely stretched and shifted in PDF (COMPLETED)
7-
- [x] #337: Fix - Title too far right in PNGs - check matplotlib placement (COMPLETED)
8-
- [x] #335: Fix - Axes wrong and no labels visible on scale_examples.html (COMPLETED)
9-
- [x] #334: Fix - No output visible on pcolormesh_demo.html (COMPLETED - PR #351)
10-
- [x] #333: Fix - Circles seem not centered with line plot in marker_demo.html (COMPLETED)
11-
- [x] #332: Fix - Dashed and dash-dotted look funny on line_styles.html (COMPLETED)
12-
- [x] #330: Fix - Old plot not cleared in second figure (figure() call) in contour_demo.html (COMPLETED)
13-
**Critical Infrastructure Issues (High Priority)**
5+
**🚨 CRITICAL CI BLOCKING: PR merge infrastructure broken**
6+
- [ ] #386: Fix - PR #369 CI failures - test-coverage and windows-test failing (URGENT)
7+
8+
**🚨 CRITICAL: CI test suite failures - user-visible rendering broken**
9+
- [ ] #382: Fix - tests fail on main CI (critical infrastructure)
10+
- [ ] #383: Fix - some examples in CI cannot write output (test infrastructure)
11+
12+
**🚨 CRITICAL: User-visible PNG/PDF rendering regressions**
13+
- [ ] #380: Fix - ylabel not rotates 90 degrees (rendering regression)
14+
- [ ] #379: Fix - no output in streamplot_demo.html (rendering regression)
15+
- [ ] #378: Fix - axes and labels at wrong place on scale_examples.html (positioning)
16+
- [ ] #375: Fix - PDF lines are outside box and axes box is upside down (PDF coordinates)
17+
- [ ] #374: Fix - no line styles visible in line_styles.html all solid (line styling)
18+
- [ ] #373: Fix - too many legend entries in second plot of legend_demo.html (legend system)
19+
- [ ] #372: Fix - all colormaps look the same on colored_contours.html (colormap system)
1420

1521
**User-Facing Issues (Medium Priority)**
22+
- [ ] #377: Enhancement - make finer grid on pcolormesh_demo.html (enhancement)
1623

1724
**Infrastructure & Documentation Issues (Lower Priority)**
1825

1926
## DOING (Current Work)
20-
- [ ] #355: Fix - First plot is empty
2127

2228
## BLOCKED (Infrastructure Issues)
29+
- [ ] #342: Refactor - complete symlog tick generation implementation (BLOCKED by PR #369 CI failures)
2330

2431
## FUTURE SPRINTS - Systematic Restoration
2532

src/fortplot_axes.f90

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ subroutine compute_symlog_ticks(data_min, data_max, threshold, tick_positions, n
126126
call add_negative_symlog_ticks(data_min, -threshold, tick_positions, num_ticks)
127127
end if
128128

129-
! Add linear region ticks
130-
if (data_min <= threshold .and. data_max >= -threshold) then
129+
! Add linear region ticks (only for the region within threshold bounds)
130+
if (max(data_min, -threshold) <= min(data_max, threshold)) then
131131
call add_linear_symlog_ticks(max(data_min, -threshold), min(data_max, threshold), &
132132
tick_positions, num_ticks)
133133
end if
@@ -200,39 +200,102 @@ function calculate_nice_step(raw_step) result(nice_step)
200200
end function calculate_nice_step
201201

202202
subroutine add_negative_symlog_ticks(data_min, upper_bound, tick_positions, num_ticks)
203+
!! Add ticks for negative logarithmic region of symlog scale
203204
real(wp), intent(in) :: data_min, upper_bound
204205
real(wp), intent(inout) :: tick_positions(MAX_TICKS)
205206
integer, intent(inout) :: num_ticks
206207

207-
! Suppress unused parameter warnings for stub implementation
208-
associate(unused_real => data_min + upper_bound, &
209-
unused_arr => tick_positions, unused_int => num_ticks); end associate
208+
real(wp) :: log_min, log_max, current_power
209+
integer :: start_power, end_power, power
210+
211+
if (data_min >= 0.0_wp .or. upper_bound >= 0.0_wp .or. upper_bound <= data_min) return
212+
213+
! Work with positive values for log calculations
214+
! For negative range [-500, -1], we want powers that give us ticks in that range
215+
log_min = log10(-upper_bound) ! log10(1) = 0 (closer to zero)
216+
log_max = log10(-data_min) ! log10(500) = ~2.7 (larger magnitude)
217+
218+
start_power = floor(log_min)
219+
end_power = ceiling(log_max)
210220

211-
! Implementation for negative symlog region (placeholder)
221+
do power = start_power, end_power
222+
if (num_ticks >= MAX_TICKS) exit
223+
current_power = -(10.0_wp**power)
224+
225+
! Check if tick is within bounds, excluding threshold boundary
226+
if (current_power >= data_min - 1.0e-10_wp .and. &
227+
current_power < upper_bound - 1.0e-10_wp) then
228+
num_ticks = num_ticks + 1
229+
tick_positions(num_ticks) = current_power
230+
end if
231+
end do
212232
end subroutine add_negative_symlog_ticks
213233

214234
subroutine add_linear_symlog_ticks(lower_bound, upper_bound, tick_positions, num_ticks)
235+
!! Add ticks for linear region of symlog scale
215236
real(wp), intent(in) :: lower_bound, upper_bound
216237
real(wp), intent(inout) :: tick_positions(MAX_TICKS)
217238
integer, intent(inout) :: num_ticks
218239

219-
! Suppress unused parameter warnings for stub implementation
220-
associate(unused_real => lower_bound + upper_bound, &
221-
unused_arr => tick_positions, unused_int => num_ticks); end associate
240+
real(wp) :: range, step, tick_value
241+
integer :: max_linear_ticks, i
242+
243+
if (upper_bound <= lower_bound) return
244+
245+
range = upper_bound - lower_bound
246+
max_linear_ticks = 5 ! Reasonable number for linear region
247+
248+
! Always include zero if it's in the range
249+
if (lower_bound <= 0.0_wp .and. upper_bound >= 0.0_wp .and. num_ticks < MAX_TICKS) then
250+
num_ticks = num_ticks + 1
251+
tick_positions(num_ticks) = 0.0_wp
252+
end if
253+
254+
! Add additional linear ticks
255+
step = range / real(max_linear_ticks + 1, wp)
256+
step = calculate_nice_step(step)
222257

223-
! Implementation for linear symlog region (placeholder)
258+
! Find first tick >= lower_bound
259+
tick_value = ceiling(lower_bound / step) * step
260+
261+
do while (tick_value <= upper_bound .and. num_ticks < MAX_TICKS)
262+
! Skip zero if already added, avoid duplicates
263+
if (abs(tick_value) > 1.0e-10_wp) then
264+
num_ticks = num_ticks + 1
265+
tick_positions(num_ticks) = tick_value
266+
end if
267+
tick_value = tick_value + step
268+
end do
224269
end subroutine add_linear_symlog_ticks
225270

226271
subroutine add_positive_symlog_ticks(lower_bound, data_max, tick_positions, num_ticks)
272+
!! Add ticks for positive logarithmic region of symlog scale
227273
real(wp), intent(in) :: lower_bound, data_max
228274
real(wp), intent(inout) :: tick_positions(MAX_TICKS)
229275
integer, intent(inout) :: num_ticks
230276

231-
! Suppress unused parameter warnings for stub implementation
232-
associate(unused_real => lower_bound + data_max, &
233-
unused_arr => tick_positions, unused_int => num_ticks); end associate
277+
real(wp) :: log_min, log_max, current_power
278+
integer :: start_power, end_power, power
279+
280+
if (lower_bound <= 0.0_wp .or. data_max <= 0.0_wp) return
234281

235-
! Implementation for positive symlog region (placeholder)
282+
log_min = log10(lower_bound)
283+
log_max = log10(data_max)
284+
285+
start_power = floor(log_min)
286+
end_power = ceiling(log_max)
287+
288+
do power = start_power, end_power
289+
if (num_ticks >= MAX_TICKS) exit
290+
current_power = 10.0_wp**power
291+
292+
! Check if tick is within bounds, excluding threshold boundary
293+
if (current_power > lower_bound + 1.0e-10_wp .and. &
294+
current_power <= data_max + 1.0e-10_wp) then
295+
num_ticks = num_ticks + 1
296+
tick_positions(num_ticks) = current_power
297+
end if
298+
end do
236299
end subroutine add_positive_symlog_ticks
237300

238301
function is_power_of_ten(value) result(is_power)

src/fortplot_rendering.f90

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ subroutine render_line_plot(backend, plot_data, plot_idx, x_min_t, x_max_t, y_mi
4040
real(wp), allocatable :: x_scaled(:), y_scaled(:)
4141
integer :: i, n
4242

43+
! Validate input data
44+
if (.not. allocated(plot_data%x) .or. .not. allocated(plot_data%y)) return
45+
if (size(plot_data%x) == 0 .or. size(plot_data%y) == 0) return
46+
if (size(plot_data%x) /= size(plot_data%y)) return
47+
4348
n = size(plot_data%x)
4449
allocate(x_scaled(n), y_scaled(n))
4550

@@ -74,6 +79,11 @@ subroutine render_markers(backend, plot_data, x_min_t, x_max_t, y_min_t, y_max_t
7479
if (.not. allocated(plot_data%marker)) return
7580
if (len_trim(plot_data%marker) == 0) return
7681

82+
! Validate input data
83+
if (.not. allocated(plot_data%x) .or. .not. allocated(plot_data%y)) return
84+
if (size(plot_data%x) == 0 .or. size(plot_data%y) == 0) return
85+
if (size(plot_data%x) /= size(plot_data%y)) return
86+
7787
! Draw markers
7888
call backend%color(plot_data%color(1), plot_data%color(2), plot_data%color(3))
7989

test/test_character_bitmap_rendering.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ program test_character_bitmap_rendering
22
!! Unit test for verifying actual character bitmap rendering correctness
33
!! Tests that characters are rendered with expected pixel patterns
44
!! Backend-agnostic test that uses high-level rendering API
5-
use fortplot_raster, only: render_text_to_bitmap
65
use fortplot_text, only: init_text_system, cleanup_text_system, calculate_text_width, calculate_text_height
6+
use fortplot_bitmap, only: render_text_to_bitmap
77
implicit none
88

99
logical :: all_tests_passed

0 commit comments

Comments
 (0)