Repository: astropy/astropy

Issue:
`DexUnit` doesn't display correctly in jupyter notebooks (worse for other log units in vscode)
### Description

I was trying to understand how logarithmic units work, so I played with them in a jupyter notebook. While I did that, I noticed that `DexUnit` doesn't display correctly in the notebook:

<img width="794" height="869" alt="Image" src="https://github.com/user-attachments/assets/714e39e3-34c7-43ad-8c98-48db40757c0b" />

It shows `ex(cm/s2` instead of `\mathrm{dex}\left( \frac{\mathrm{cm}}{\mathrm{s}^2} \right)` like the other log units. You can also see that the call to `_repr_latex_` (which I think is what jupyter uses to render the result) returns a simple 'dex' instead of all the necessary LaTeX commands like the others.

After digging through the source code, I think I found the cause of the issue. In the [source](https://github.com/astropy/astropy/blob/main/astropy/units/function/logarithmic.py#L190) of `DexUnit`, the super call to `to_string` doesn't pass the given `format` argument, so the super call receives the default value of 'generic' instead of 'latex'. I tested it in a debugger where I changed the argument's value to 'latex' at runtime, and I got the correct rendering.

However, there is another issue with the rendering of log units, which is only visible in VSCode. The same notebook I showed above gives this in VSCode:

<img width="709" height="931" alt="Image" src="https://github.com/user-attachments/assets/e417001f-308d-4f2a-b220-4bfaa9a28156" />

VSCode doesn't render even the correct log units, but instead just prints the LaTeX code. After digging a bit, I found that the '$$' in the middle of the latex output is the culprit. Apparently, VSCode's engine can't understand two consecutive dollar signs like here. You can see in the last cell that removing the double dollar signs in the middle or putting a space between them fixes the rendering in VSCode. While it's certainly an issue with VSCode's renderer, I need to ask why there are double dollar signs in the first place. I think it's an easy fix to remove the dollar signs in the middle or at least put a space between them since they're unrelated.

### Expected behavior

The `DexUnit` should render correctly, and all the log units should render correctly in both JupyterLab and VSCode.

### How to Reproduce

Simply try to output something with `DexUnit` in a notebook and try to output any other log units in a notebook in VSCode.

### Versions

```python
import astropy
astropy.system_info()
```
```
platform
--------
platform.platform() = 'macOS-15.6.1-arm64-arm-64bit-Mach-O'
platform.version() = 'Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:34 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T8103'
platform.python_version() = '3.13.3'

packages
--------
astropy              7.1.0
numpy                2.3.3
scipy                --
matplotlib           --
pandas               --
pyerfa               2.0.1.5
```

Discussion:
pllim: Doesn't seem to quite work?

```
>       dex = u.Dex(u.cm / u.s**2)
              ^^^^^^^^^^^^^^^^^^^^
...
E           TypeError: The value must be a valid Python or Numpy numeric type.
```

Also please add a change log (https://github.com/astropy/astropy/blob/main/docs/changes/README.rst). Thanks!

Fix (patch):
diff --git a/astropy/units/function/core.py b/astropy/units/function/core.py
index 44f24b0bf0..ed1a546250 100644
--- a/astropy/units/function/core.py
+++ b/astropy/units/function/core.py
@@ -419,8 +419,10 @@ class FunctionUnitBase(metaclass=ABCMeta):
         if pu_str == "":
             pu_str = "1"
         if format.startswith("latex"):
-            # need to strip leading and trailing "$"
-            self_str += rf"$\mathrm{{\left( {pu_str[1:-1]} \right)}}$"
+            # Add the physical unit with parentheses, removing its latex
+            # initialization stuff ("$\mathrm{" and "}$").
+            # For self_str, remove trailing "}$" and put it back at the end.
+            self_str = rf"{self_str[:-2]}\left({pu_str[9:-2]}\right)}}$"
         else:
             pu_lines = pu_str.splitlines()
             if len(pu_lines) == 1:
diff --git a/astropy/units/function/logarithmic.py b/astropy/units/function/logarithmic.py
index 66665be997..a17ff304fd 100644
--- a/astropy/units/function/logarithmic.py
+++ b/astropy/units/function/logarithmic.py
@@ -187,7 +187,7 @@ class DexUnit(LogUnit):
             else:
                 return f"[{self.physical_unit.to_string(format=format)}]"
         else:
-            return super().to_string()
+            return super().to_string(format=format)
 
 
 class DecibelUnit(LogUnit):
diff --git a/docs/changes/units/18627.bugfix.rst b/docs/changes/units/18627.bugfix.rst
new file mode 100644
index 0000000000..90d4090d59
--- /dev/null
+++ b/docs/changes/units/18627.bugfix.rst
@@ -0,0 +1,2 @@
+Fixed the LaTeX representation of ``DexUnit`` in ``astropy.units``,
+and thus also how it is represented in, e.g., jupyter notebooks.


Test changes:
diff --git a/astropy/units/tests/test_format.py b/astropy/units/tests/test_format.py
index 1f1fd5250c..391d6a649b 100644
--- a/astropy/units/tests/test_format.py
+++ b/astropy/units/tests/test_format.py
@@ -1137,8 +1137,8 @@ def test_celsius_fits():
     "test_pair",
     list_format_string_pairs(
         ("generic", "dB(1 / m)"),
-        ("latex", r"$\mathrm{dB}$$\mathrm{\left( \mathrm{\frac{1}{m}} \right)}$"),
-        ("latex_inline", r"$\mathrm{dB}$$\mathrm{\left( \mathrm{m^{-1}} \right)}$"),
+        ("latex", r"$\mathrm{dB\left(\frac{1}{m}\right)}$"),
+        ("latex_inline", r"$\mathrm{dB\left(m^{-1}\right)}$"),
         ("console", "dB(m^-1)"),
         ("unicode", "dB(m⁻¹)"),
     ),
@@ -1157,8 +1157,8 @@ def test_function_format_styles(test_pair: FormatStringPair):
         ("console", "inline", "dB(1 / m)"),
         ("unicode", "multiline", "   1\ndB(─)\n   m"),
         ("unicode", "inline", "dB(1 / m)"),
-        ("latex", False, r"$\mathrm{dB}$$\mathrm{\left( \mathrm{m^{-1}} \right)}$"),
-        ("latex", "inline", r"$\mathrm{dB}$$\mathrm{\left( \mathrm{1 / m} \right)}$"),
+        ("latex", False, r"$\mathrm{dB\left(m^{-1}\right)}$"),
+        ("latex", "inline", r"$\mathrm{dB\left(1 / m\right)}$"),
     ],
 )
 def test_function_format_styles_non_default_fraction(format_spec, fraction, string):
diff --git a/astropy/units/tests/test_logarithmic.py b/astropy/units/tests/test_logarithmic.py
index db4a0b1cfb..6d600418e3 100644
--- a/astropy/units/tests/test_logarithmic.py
+++ b/astropy/units/tests/test_logarithmic.py
@@ -196,18 +196,24 @@ class TestLogUnitStrings:
 
         lu4 = u.mag(u.ct)
         assert lu4.to_string("generic") == "mag(ct)"
-        latex_str = r"$\mathrm{mag}$$\mathrm{\left( \mathrm{ct} \right)}$"
+        latex_str = r"$\mathrm{mag\left(ct\right)}$"
         assert lu4.to_string("latex") == latex_str
         assert lu4.to_string("latex_inline") == latex_str
         assert lu4._repr_latex_() == latex_str
 
         lu5 = u.mag(u.ct / u.s)
-        assert lu5.to_string("latex") == (
-            r"$\mathrm{mag}$$\mathrm{\left( \mathrm{\frac{ct}{s}} \right)}$"
-        )
-        latex_str = r"$\mathrm{mag}$$\mathrm{\left( \mathrm{ct\,s^{-1}} \right)}$"
+        latex_str = r"$\mathrm{mag\left(\frac{ct}{s}\right)}$"
+        assert lu5.to_string("latex") == latex_str
+        latex_str = r"$\mathrm{mag\left(ct\,s^{-1}\right)}$"
         assert lu5.to_string("latex_inline") == latex_str
 
+    def test_dex_latex_str(self):
+        # Regression test for gh-18618.
+        lu = u.dex(u.cm / u.s**2)
+        latex_str = r"$\mathrm{dex\left(\frac{cm}{s^{2}}\right)}$"
+        assert lu.to_string(format="latex") == latex_str
+        assert lu._repr_latex_() == latex_str
+
 
 class TestLogUnitConversion:
     @pytest.mark.parametrize("physical_unit", pu_sample)