Repository: matplotlib/matplotlib

Issue:
[Bug]: ScalarFormatter cant be forced to use an offset of 1
### Bug summary

The ScalarFormatter class takes an argument useOffset, either True, which will determine an automatic offset, False, which disables an offset or an numeric value, which is the used as an offset.
Since in python 1 == True --> True, trying to pass a numeric offset value of 1 just enables the automatic offset.

https://matplotlib.org/stable/api/ticker_api.html#matplotlib.ticker.ScalarFormatter

### Code for reproduction

```Python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import ScalarFormatter

# Sample data
x = np.linspace(0, 10, 100)
y = np.linspace(0.999, 1.001, 100)

# Create the plot
fig, ax = plt.subplots()
ax.plot(x, y)

formatter = ScalarFormatter()
formatter.set_useOffset(1)
# identical to formatter = ScalarFormatter(useOffset=1)
ax.yaxis.set_major_formatter(formatter)

plt.show()
```

### Actual outcome

![Image](https://github.com/user-attachments/assets/a20a17cc-0605-4f14-b8e3-db1b3ec33c52)

### Expected outcome

The y-Axis should be centered around zero, the expected offset of 1 is not used

### Additional information

Happens only for useOffset = 1.
If the y values are changed (i.e. y = np.linspace(0.99999, 1.00001, 100)), the automatic offset actually uses an offset of 1, so the bug is not obvious then.

### Operating system

Win 11

### Matplotlib Version

3.7.2

### Matplotlib Backend

module://matplotlib_inline.backend_inline

### Python version

_No response_

### Jupyter version

6.5.4

### Installation

conda


Discussion:
I think this is a good first issue and the task is

1. Change this line to check for a `bool` instance
https://github.com/matplotlib/matplotlib/blob/29f3a5ca0bd366d5bffebfcfba6181af322041b3/lib/matplotlib/ticker.py#L513

2.  Add a test

Thanks for the clear report @FelixKeiser 
### Good first issue - notes for new contributors

This issue is suited to new contributors because it does not require understanding of the
Matplotlib internals. To get started, please see our [contributing
guide](https://matplotlib.org/stable/devel/index).

**We do not assign issues**. Check the *Development* section in the sidebar for linked pull
requests (PRs). If there are none, feel free to start working on it. If there is an open PR, please
collaborate on the work by reviewing it rather than duplicating it in a competing PR.

If something is unclear, please reach out on any of our [communication
channels](https://matplotlib.org/stable/devel/contributing.html#get-connected).
Ok but 1 should evaluate to True, whereas 1.0 should be recognized as a float.  
> Ok but 1 should evaluate to True, whereas 1.0 should be recognized as a float.

Sadly no, 1.0 == True still evaluates to True, same with float(1) == True or similar attempts.
Even if it would work, it would still be very unintuitive and would lead to errors
Ok that's surprising.  Learn something new every day.  
As a workaround though until this is fixed, you _can_ do `formatter.set_useOffset(1.0+1e-13)`
Thank you, that is basically what I have been doing for now



Patch:
diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py
index 231479092461..4eb9a2e66c01 100644
--- a/lib/matplotlib/ticker.py
+++ b/lib/matplotlib/ticker.py
@@ -510,7 +510,7 @@ def set_useOffset(self, val):
         will be formatted as ``0, 2, 4, 6, 8`` plus an offset ``+1e5``, which
         is written to the edge of the axis.
         """
-        if val in [True, False]:
+        if isinstance(val, bool):
             self.offset = 0
             self._useOffset = val
         else:


Test patch:
diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py
index 12142b6edc04..2136015cf1b1 100644
--- a/lib/matplotlib/tests/test_ticker.py
+++ b/lib/matplotlib/tests/test_ticker.py
@@ -859,6 +859,22 @@ def test_set_use_offset_float(self):
         assert not tmp_form.get_useOffset()
         assert tmp_form.offset == 0.5
 
+    def test_set_use_offset_bool(self):
+        tmp_form = mticker.ScalarFormatter()
+        tmp_form.set_useOffset(True)
+        assert tmp_form.get_useOffset()
+        assert tmp_form.offset == 0
+
+        tmp_form.set_useOffset(False)
+        assert not tmp_form.get_useOffset()
+        assert tmp_form.offset == 0
+
+    def test_set_use_offset_int(self):
+        tmp_form = mticker.ScalarFormatter()
+        tmp_form.set_useOffset(1)
+        assert not tmp_form.get_useOffset()
+        assert tmp_form.offset == 1
+
     def test_use_locale(self):
         conv = locale.localeconv()
         sep = conv['thousands_sep']