Shared legend layout calculations following DRY principle
Single Responsibility: Legend box sizing and positioning calculations DRY: Centralized legend layout logic for consistent behavior KISS: Simple, clear calculation functions Uses text system measurements for accurate sizing
Single Responsibility: Legend box dimensions and position
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | public | :: | x | ||||
| real(kind=wp), | public | :: | y | ||||
| real(kind=wp), | public | :: | width | ||||
| real(kind=wp), | public | :: | height | ||||
| real(kind=wp), | public | :: | padding | ||||
| real(kind=wp), | public | :: | padding_x | ||||
| real(kind=wp), | public | :: | entry_height | ||||
| real(kind=wp), | public | :: | entry_spacing | ||||
| real(kind=wp), | public | :: | line_length | ||||
| real(kind=wp), | public | :: | text_spacing |
Calculate optimal legend box dimensions and position DRY: Centralized legend box calculation logic
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | labels(:) | |||
| real(kind=wp), | intent(in) | :: | data_width | |||
| real(kind=wp), | intent(in) | :: | data_height | |||
| integer, | intent(in) | :: | num_entries | |||
| integer, | intent(in) | :: | position | |||
| integer, | intent(in), | optional | :: | pixel_plot_width | ||
| integer, | intent(in), | optional | :: | pixel_plot_height |
Resolve matplotlib 'best' placement to a concrete corner. Computes the legend box for each candidate corner and scores it by the number of plotted artist sample points its bbox covers; the lowest overlap wins, ties broken in matplotlib's order (upper right first).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | labels(:) | |||
| real(kind=wp), | intent(in) | :: | data_width | |||
| real(kind=wp), | intent(in) | :: | data_height | |||
| integer, | intent(in) | :: | num_entries | |||
| real(kind=wp), | intent(in) | :: | artist_x(:) | |||
| real(kind=wp), | intent(in) | :: | artist_y(:) | |||
| integer, | intent(in), | optional | :: | pixel_plot_width | ||
| integer, | intent(in), | optional | :: | pixel_plot_height |
Get actual text dimensions using text system measurements
Returns [width, height] in data coordinates
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | label | |||
| real(kind=wp), | intent(in) | :: | data_to_pixel_x | |||
| real(kind=wp), | intent(in) | :: | data_to_pixel_y |
Inset between the legend box and the axes frame. Matches matplotlib's borderaxespad default (0.5 * 10pt font = 5pt), which at the standard ~100 dpi is ~7 px, independent of the data range. A fixed pixel inset keeps the legend flush in the corner the way matplotlib draws it, instead of a large data-proportional gap.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | data_width | |||
| real(kind=wp), | intent(in) | :: | data_height | |||
| integer, | intent(in), | optional | :: | pixel_plot_width | ||
| integer, | intent(in), | optional | :: | pixel_plot_height |
Calculate optimal legend dimensions using actual text system measurements KISS: Based on measured text content, not estimates
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | labels(:) | |||
| real(kind=wp), | intent(in) | :: | data_width | |||
| real(kind=wp), | intent(in) | :: | data_height | |||
| real(kind=wp), | intent(out) | :: | max_text_width | |||
| real(kind=wp), | intent(out) | :: | total_text_width | |||
| type(legend_box_t), | intent(inout) | :: | box | |||
| integer, | intent(in) | :: | pixel_plot_width | |||
| integer, | intent(in) | :: | pixel_plot_height |