Skip to content

Commit 26ea88b

Browse files
Fix tick marker mirroring
1 parent d3105d4 commit 26ea88b

3 files changed

Lines changed: 90 additions & 10 deletions

File tree

plotly/matplotlylib/mpltools.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -250,15 +250,12 @@ def get_axes_bounds(fig):
250250
return (x_min, x_max), (y_min, y_max)
251251

252252

253-
def get_axis_mirror(main_spine, mirror_spine):
254-
if main_spine and mirror_spine:
253+
def get_axis_mirror(main_spine, mirror_spine, main_tick_markers, mirror_tick_markers):
254+
if main_spine and mirror_spine and main_tick_markers and mirror_tick_markers:
255255
return "ticks"
256-
elif main_spine and not mirror_spine:
257-
return False
258-
elif not main_spine and mirror_spine:
259-
return False # can't handle this case yet!
260-
else:
261-
return False # nuttin'!
256+
if main_spine and mirror_spine:
257+
return True
258+
return False
262259

263260

264261
def get_bar_gap(bar_starts, bar_ends, tol=1e-10):

plotly/matplotlylib/renderer.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,16 @@ def open_axes(self, ax, props):
186186
top_spine = mpltools.get_spine_visible(ax, "top")
187187
left_spine = mpltools.get_spine_visible(ax, "left")
188188
right_spine = mpltools.get_spine_visible(ax, "right")
189-
xaxis["mirror"] = mpltools.get_axis_mirror(bottom_spine, top_spine)
190-
yaxis["mirror"] = mpltools.get_axis_mirror(left_spine, right_spine)
189+
bottom_tick_markers = ax.xaxis.get_tick_params()["bottom"]
190+
top_tick_markers = ax.xaxis.get_tick_params()["top"]
191+
left_tick_markers = ax.yaxis.get_tick_params()["left"]
192+
right_tick_markers = ax.yaxis.get_tick_params()["right"]
193+
xaxis["mirror"] = mpltools.get_axis_mirror(
194+
bottom_spine, top_spine, bottom_tick_markers, top_tick_markers
195+
)
196+
yaxis["mirror"] = mpltools.get_axis_mirror(
197+
left_spine, right_spine, left_tick_markers, right_tick_markers
198+
)
191199
xaxis["showline"] = bottom_spine
192200
yaxis["showline"] = top_spine
193201

plotly/matplotlylib/tests/test_renderer.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,81 @@ def test_multiple_traces_native_legend():
8989
assert plotly_fig.data[2].mode == "lines+markers"
9090

9191

92+
93+
def test_axis_mirror_with_spines_and_ticks():
94+
"""Test that mirror=True when both spines and ticks are visible on both sides."""
95+
fig, ax = plt.subplots()
96+
ax.plot([0, 1], [0, 1])
97+
98+
# Show all spines
99+
ax.spines["top"].set_visible(True)
100+
ax.spines["bottom"].set_visible(True)
101+
ax.spines["left"].set_visible(True)
102+
ax.spines["right"].set_visible(True)
103+
104+
# Show ticks on all sides
105+
ax.tick_params(top=True, bottom=True, left=True, right=True)
106+
107+
plotly_fig = tls.mpl_to_plotly(fig)
108+
109+
assert plotly_fig.layout.xaxis.mirror == "ticks"
110+
assert plotly_fig.layout.yaxis.mirror == "ticks"
111+
112+
113+
def test_axis_mirror_with_ticks_only():
114+
"""Test that mirror=False when spines are not visible on both sides."""
115+
fig, ax = plt.subplots()
116+
ax.plot([0, 1], [0, 1])
117+
118+
# Hide opposite spines
119+
ax.spines["top"].set_visible(False)
120+
ax.spines["right"].set_visible(False)
121+
122+
# Show ticks on all sides
123+
ax.tick_params(top=True, bottom=True, left=True, right=True)
124+
125+
plotly_fig = tls.mpl_to_plotly(fig)
126+
127+
assert plotly_fig.layout.xaxis.mirror == False
128+
assert plotly_fig.layout.yaxis.mirror == False
129+
130+
131+
def test_axis_mirror_false_with_one_sided_ticks():
132+
"""Test that mirror=True when ticks are only on one side but spines are
133+
visible on both sides."""
134+
fig, ax = plt.subplots()
135+
ax.plot([0, 1], [0, 1])
136+
137+
# Default matplotlib behavior - ticks only on bottom and left
138+
ax.tick_params(top=False, bottom=True, left=True, right=False)
139+
140+
plotly_fig = tls.mpl_to_plotly(fig)
141+
142+
assert plotly_fig.layout.xaxis.mirror == True
143+
assert plotly_fig.layout.yaxis.mirror == True
144+
145+
146+
def test_axis_mirror_mixed_configurations():
147+
"""Test different configurations for x and y axes."""
148+
fig, ax = plt.subplots()
149+
ax.plot([0, 1], [0, 1])
150+
151+
# X-axis: spines and ticks on both sides (mirror="ticks")
152+
ax.spines["top"].set_visible(True)
153+
ax.spines["bottom"].set_visible(True)
154+
ax.tick_params(top=True, bottom=True)
155+
156+
# Y-axis: spine only on one side (mirror=False)
157+
ax.spines["right"].set_visible(False)
158+
ax.spines["left"].set_visible(True)
159+
ax.tick_params(left=True, right=True)
160+
161+
plotly_fig = tls.mpl_to_plotly(fig)
162+
163+
assert plotly_fig.layout.xaxis.mirror == "ticks"
164+
assert plotly_fig.layout.yaxis.mirror == False
165+
166+
92167
def test_violinplot_bodies_are_filled_polygons():
93168
fig, ax = plt.subplots()
94169
ax.violinplot(np.random.randn(100, 3))

0 commit comments

Comments
 (0)