Skip to content

Commit c65428b

Browse files
Fix tick marker mirroring
1 parent bf29422 commit c65428b

File tree

3 files changed

+89
-10
lines changed

3 files changed

+89
-10
lines changed

plotly/matplotlylib/mpltools.py

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

267267

268-
def get_axis_mirror(main_spine, mirror_spine):
269-
if main_spine and mirror_spine:
268+
def get_axis_mirror(main_spine, mirror_spine, main_tick_markers, mirror_tick_markers):
269+
if main_spine and mirror_spine and main_tick_markers and mirror_tick_markers:
270270
return "ticks"
271-
elif main_spine and not mirror_spine:
272-
return False
273-
elif not main_spine and mirror_spine:
274-
return False # can't handle this case yet!
275-
else:
276-
return False # nuttin'!
271+
if main_spine and mirror_spine:
272+
return True
273+
return False
277274

278275

279276
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
@@ -169,8 +169,16 @@ def open_axes(self, ax, props):
169169
top_spine = mpltools.get_spine_visible(ax, "top")
170170
left_spine = mpltools.get_spine_visible(ax, "left")
171171
right_spine = mpltools.get_spine_visible(ax, "right")
172-
xaxis["mirror"] = mpltools.get_axis_mirror(bottom_spine, top_spine)
173-
yaxis["mirror"] = mpltools.get_axis_mirror(left_spine, right_spine)
172+
bottom_tick_markers = ax.xaxis.get_tick_params()["bottom"]
173+
top_tick_markers = ax.xaxis.get_tick_params()["top"]
174+
left_tick_markers = ax.yaxis.get_tick_params()["left"]
175+
right_tick_markers = ax.yaxis.get_tick_params()["right"]
176+
xaxis["mirror"] = mpltools.get_axis_mirror(
177+
bottom_spine, top_spine, bottom_tick_markers, top_tick_markers
178+
)
179+
yaxis["mirror"] = mpltools.get_axis_mirror(
180+
left_spine, right_spine, left_tick_markers, right_tick_markers
181+
)
174182
xaxis["showline"] = bottom_spine
175183
yaxis["showline"] = top_spine
176184

plotly/matplotlylib/tests/test_renderer.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,77 @@ def test_multiple_traces_native_legend():
8484
assert plotly_fig.data[0].mode == "lines"
8585
assert plotly_fig.data[1].mode == "markers"
8686
assert plotly_fig.data[2].mode == "lines+markers"
87+
88+
89+
def test_axis_mirror_with_spines_and_ticks():
90+
"""Test that mirror=True when both spines and ticks are visible on both sides."""
91+
fig, ax = plt.subplots()
92+
ax.plot([0, 1], [0, 1])
93+
94+
# Show all spines
95+
ax.spines['top'].set_visible(True)
96+
ax.spines['bottom'].set_visible(True)
97+
ax.spines['left'].set_visible(True)
98+
ax.spines['right'].set_visible(True)
99+
100+
# Show ticks on all sides
101+
ax.tick_params(top=True, bottom=True, left=True, right=True)
102+
103+
plotly_fig = tls.mpl_to_plotly(fig)
104+
105+
assert plotly_fig.layout.xaxis.mirror == "ticks"
106+
assert plotly_fig.layout.yaxis.mirror == "ticks"
107+
108+
109+
def test_axis_mirror_with_ticks_only():
110+
"""Test that mirror=False when spines are not visible on both sides."""
111+
fig, ax = plt.subplots()
112+
ax.plot([0, 1], [0, 1])
113+
114+
# Hide opposite spines
115+
ax.spines['top'].set_visible(False)
116+
ax.spines['right'].set_visible(False)
117+
118+
# Show ticks on all sides
119+
ax.tick_params(top=True, bottom=True, left=True, right=True)
120+
121+
plotly_fig = tls.mpl_to_plotly(fig)
122+
123+
assert plotly_fig.layout.xaxis.mirror == False
124+
assert plotly_fig.layout.yaxis.mirror == False
125+
126+
127+
def test_axis_mirror_false_with_one_sided_ticks():
128+
"""Test that mirror=True when ticks are only on one side but spines are
129+
visible on both sides."""
130+
fig, ax = plt.subplots()
131+
ax.plot([0, 1], [0, 1])
132+
133+
# Default matplotlib behavior - ticks only on bottom and left
134+
ax.tick_params(top=False, bottom=True, left=True, right=False)
135+
136+
plotly_fig = tls.mpl_to_plotly(fig)
137+
138+
assert plotly_fig.layout.xaxis.mirror == True
139+
assert plotly_fig.layout.yaxis.mirror == True
140+
141+
142+
def test_axis_mirror_mixed_configurations():
143+
"""Test different configurations for x and y axes."""
144+
fig, ax = plt.subplots()
145+
ax.plot([0, 1], [0, 1])
146+
147+
# X-axis: spines and ticks on both sides (mirror="ticks")
148+
ax.spines['top'].set_visible(True)
149+
ax.spines['bottom'].set_visible(True)
150+
ax.tick_params(top=True, bottom=True)
151+
152+
# Y-axis: spine only on one side (mirror=False)
153+
ax.spines['right'].set_visible(False)
154+
ax.spines['left'].set_visible(True)
155+
ax.tick_params(left=True, right=True)
156+
157+
plotly_fig = tls.mpl_to_plotly(fig)
158+
159+
assert plotly_fig.layout.xaxis.mirror == "ticks"
160+
assert plotly_fig.layout.yaxis.mirror == False

0 commit comments

Comments
 (0)