Skip to content

Commit

Permalink
Improve get_axis_range algorithm. Other minor clean up.
Browse files Browse the repository at this point in the history
  • Loading branch information
nealkruis committed May 10, 2024
1 parent c926a74 commit 976e9a7
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 10 deletions.
37 changes: 27 additions & 10 deletions dimes/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from dataclasses import dataclass
import warnings
from datetime import datetime
import math
import bisect

from plotly.graph_objects import Figure, Scatter # type: ignore

Expand Down Expand Up @@ -110,6 +112,7 @@ def __init__(
is_visible: bool = True,
legend_group: Union[str, None] = None,
x_axis: Union[DimensionalData, TimeSeriesAxis, List[SupportsFloat], List[datetime], None] = None,
y_axis_min: Union[SupportsFloat, None] = 0.0,
):
super().__init__(data_values, name, native_units, display_units)
self.x_axis: Union[DimensionalData, TimeSeriesAxis, None]
Expand All @@ -120,6 +123,7 @@ def __init__(
self.x_axis = DimensionalData(x_axis) # type: ignore[arg-type]
else:
self.x_axis = x_axis
self.y_axis_min = y_axis_min
self.line_properties = line_properties
self.is_visible = is_visible
self.legend_group = legend_group
Expand All @@ -142,9 +146,19 @@ def get_axis_label(self) -> str:

@staticmethod
def get_axis_range(value_min, value_max):
range_buffer = 0.1
range_values = value_max - value_min
return [value_min - range_values * range_buffer, value_max + range_values * range_buffer]
max_ticks = 6
tick_scale_options = [1, 2, 5, 10]

value_range = value_max - value_min
min_tick_size = value_range / max_ticks
magnitude = 10 ** math.floor(math.log(min_tick_size, 10))
residual = min_tick_size / magnitude
tick_size = (
tick_scale_options[bisect.bisect_right(tick_scale_options, residual)] if residual < 10 else 10
) * magnitude
range_min = math.floor(value_min / tick_size) * tick_size
range_max = math.ceil(value_max / tick_size) * tick_size
return [range_min, range_max]


class DimensionalSubplot:
Expand Down Expand Up @@ -234,9 +248,7 @@ def finalize_plot(self):
"mirror": True,
"linecolor": BLACK,
"linewidth": grid_line_width,
"zeroline": True,
"zerolinecolor": GREY,
"zerolinewidth": grid_line_width,
"zeroline": False,
}
x_axis_label = f"{self.x_axis.name}"
if isinstance(self.x_axis, DimensionalData):
Expand All @@ -257,6 +269,11 @@ def finalize_plot(self):
axis.units,
)
axis.range_min = min(min(y_values), axis.range_min)
if display_data.y_axis_min is not None:
data_y_axis_min = koozie.convert(
display_data.y_axis_min, display_data.native_units, axis.units
)
axis.range_min = min(data_y_axis_min, axis.range_min)
axis.range_max = max(max(y_values), axis.range_max)
if display_data.x_axis is None:
if isinstance(display_data.x_axis, DimensionalData):
Expand Down Expand Up @@ -333,10 +350,10 @@ def finalize_plot(self):
"domain": [0.0, 1.0],
"matches": (f"x{number_of_subplots}" if subplot_number < number_of_subplots else None),
"showticklabels": None if is_last_subplot else False,
"ticks": "outside",
"tickson": "boundaries",
"tickcolor": BLACK,
"tickwidth": grid_line_width,
"ticks": None if not is_last_subplot else "outside",
"tickson": None if not is_last_subplot else "boundaries",
"tickcolor": None if not is_last_subplot else BLACK,
"tickwidth": None if not is_last_subplot else grid_line_width,
}
self.figure.layout[f"xaxis{x_axis_id}"].update(xy_common_axis_format)
else:
Expand Down
10 changes: 10 additions & 0 deletions test/test_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pathlib import Path
import pytest
from dimes import TimeSeriesPlot, TimeSeriesData, LineProperties, LinesOnly
from dimes.common import DimensionalAxis

TESTING_DIRECTORY = Path("test_outputs")
TESTING_DIRECTORY.mkdir(exist_ok=True)
Expand Down Expand Up @@ -174,3 +175,12 @@ def test_is_visible():
)
)
plot.write_html_plot(Path(TESTING_DIRECTORY, "is_visible.html"))


def test_get_axis_range():
checks = [([0, 2], [0, 2]), ([0, 23.5], [0, 25])]

for check in checks:
min_value = check[0][0]
max_value = check[0][1]
assert DimensionalAxis.get_axis_range(min_value, max_value) == check[1]

0 comments on commit 976e9a7

Please sign in to comment.