Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Implement xtick and ytick rotation modes#28968

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged

Conversation

kyracho
Copy link
Contributor

@kyrachokyracho commentedOct 11, 2024
edited
Loading

Hello, the goal of this PR is to implement two newrotation_mode types'xtick' and'ytick' for the axis labels.
The idea is that these new rotation_modes automatically set the label alignments to match anyrotation in$[0,360)$.'xtick' aligns the x-axis labels, and 'ytick' aligns the y-axis labels.

Closes#28951

Plots illustrating the proposed'xtick' and'ytick' rotation modes:

For bottom and left labels:

importmatplotlib.pyplotaspltimportnumpyasnpt=np.linspace(0,2*np.pi,1000)r=np.cos(6*t)x_flower=r*np.cos(t)y_flower=r*np.sin(t)angles,n_cols=np.linspace(0,360,25),5fig,axs=plt.subplots(nrows=5,ncols=n_cols,figsize=(30,30))axs=axs.flatten()labels= ['label'foriinrange(8)]fori,angleinenumerate(angles):ax=axs[i]ax.set_title(f'Rotation:{angle:.0f}°',fontsize=10)ax.set_xticks(np.linspace(0,1.3,8).tolist())ax.set_xticklabels(labels)# ax.xaxis.tick_top()ax.xaxis.set_tick_params(rotation=angle,rotation_mode='xtick')ax.set_yticks(np.linspace(0,1.3,8).tolist())ax.set_yticklabels(labels)# ax.yaxis.tick_right()ax.yaxis.set_tick_params(rotation=angle,rotation_mode='ytick')ax.set_xlim(0,1.3)ax.set_ylim(0,1.3)ax.plot(x_flower*0.5+0.65,y_flower*0.5+0.65,color='purple')plt.tight_layout()plt.savefig('rotated_ticks_figure')plt.show()

rotated_ticks_figure-4

For top and right labels:

importmatplotlib.pyplotaspltimportnumpyasnpt=np.linspace(0,2*np.pi,1000)r=np.cos(6*t)x_flower=r*np.cos(t)y_flower=r*np.sin(t)angles,n_cols=np.linspace(0,360,25),5fig,axs=plt.subplots(nrows=5,ncols=n_cols,figsize=(30,30))axs=axs.flatten()labels= ['label'foriinrange(8)]fori,angleinenumerate(angles):ax=axs[i]ax.set_title(f'Rotation:{angle:.0f}°',fontsize=10)ax.set_xticks(np.linspace(0,1.3,8).tolist())ax.set_xticklabels(labels)ax.xaxis.tick_top()ax.xaxis.set_tick_params(rotation=angle,rotation_mode='xtick')ax.set_yticks(np.linspace(0,1.3,8).tolist())ax.set_yticklabels(labels)ax.yaxis.tick_right()ax.yaxis.set_tick_params(rotation=angle,rotation_mode='ytick')ax.set_xlim(0,1.3)ax.set_ylim(0,1.3)ax.plot(x_flower*0.5+0.65,y_flower*0.5+0.65,color='purple')plt.tight_layout()plt.savefig('rotated_ticks_figure')plt.show()

rotated_ticks_figure-3

PR checklist

@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch from92c0a43 toee92312CompareOctober 11, 2024 11:47
@kyrachokyracho marked this pull request as draftOctober 11, 2024 12:08
@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch 2 times, most recently from9356808 toefc02caCompareOctober 13, 2024 03:01
@kyrachokyracho changed the titleImplement xtick rotation modeImplement xtick and ytick rotation modesOct 13, 2024
@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch 3 times, most recently from03d0f37 tofe4a1c0CompareOctober 13, 2024 12:06
Copy link
Contributor

@scottshambaughscottshambaugh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This is looking pretty good I think! I know this is still a draft so apologies if I'm jumping the gun with a review, but please add:

kyracho reacted with thumbs up emoji
@@ -1380,6 +1386,30 @@ def set_fontname(self, fontname):
"""
self.set_fontfamily(fontname)

def ha_for_angle(self, angle):
Copy link
Contributor

@scottshambaughscottshambaughOct 15, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

angle here and below should be restricted to [0, 360) deg. Docstring should also call out thatangle is measured in degrees

kyracho reacted with thumbs up emoji
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I don't think this is being covered yet - the angle input here and the va function should be wrapped to [0, 360). In other words:angle = angle % 360

kyracho reacted with thumbs up emoji
Copy link
ContributorAuthor

@kyrachokyrachoOct 21, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Sorry if I didn't mention this earlier! Matplotlib already applies the modulo operation to the input angle before it reaches_ha_for_angle and_va_for_angle. It applies the modulo operation here:

defset_rotation(self,s):"""        Set the rotation of the text.        Parameters        ----------        s : float or {'vertical', 'horizontal'}            The rotation angle in degrees in mathematically positive direction            (counterclockwise). 'horizontal' equals 0, 'vertical' equals 90.        """ifisinstance(s,Real):self._rotation=float(s)%360elifcbook._str_equal(s,'horizontal')orsisNone:self._rotation=0.elifcbook._str_equal(s,'vertical'):self._rotation=90.else:raiseValueError("rotation must be 'vertical', 'horizontal' or "f"a number, not{s}")self.stale=True

Example

Temporarily adding print statements:

def_ha_for_angle(self,angle,is_tick_top_enabled):"""        Determines horizontal alignment ('ha') based on the angle of rotation        in degrees. Adjusts for is_tick_top_enabled.        """print('angle:',angle)if (angle<5or85<=angle<105or355<=angle<360or170<=angle<190or265<=angle<275):return'center'elif5<=angle<85or190<=angle<265:return'left'ifis_tick_top_enabledelse'right'return'right'ifis_tick_top_enabledelse'left'def_va_for_angle(self,angle,is_tick_right_enabled):"""        Determines vertical alignment ('va') based on the angle of rotation        in degrees. Adjusts for is_tick_right_enabled.        """print('angle:',angle)if (angle<5or355<=angle<360or170<=angle<190or85<=angle<105or265<=angle<275):return'center'elif190<=angle<265or5<=angle<85:return'baseline'ifis_tick_right_enabledelse'top'return'top'ifis_tick_right_enabledelse'baseline'

Exercising the code path:

importmatplotlib.pyplotaspltimportnumpyasnpangles,n_cols=np.linspace(-45,405,2),2fig,axs=plt.subplots(nrows=1,ncols=n_cols,figsize=(4,2.5))axs=axs.flatten()fori,angleinenumerate(angles):ax=axs[i]ax.set_title(f'Rotation:{angle:.0f}°',fontsize=10)ax.set_xticks([0.5])ax.set_xticklabels(['L'])ax.xaxis.set_tick_params(rotation=angle,rotation_mode='xtick')ax.set_yticks([0.5])ax.set_yticklabels(['L'])ax.yaxis.set_tick_params(rotation=angle,rotation_mode='ytick')plt.savefig('rotated_ticks_figure.png')plt.show()

rotated_ticks_figure

Terminal:

angle: 315.0angle: 45.0

I restricted the covered angles to [0,360) from [0,360] based on your suggestion. If you still want the modulo operations to be added to_va_for_angle and_ha_for_angle as a precaution, let me know. Thanks!

scottshambaugh reacted with thumbs up emoji
@anntzer
Copy link
Contributor

I didn't actually check the implementation, but does this also work with ticks on the right or the top?

kyracho reacted with thumbs up emoji

@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch 2 times, most recently from43d9c02 toe451e7fCompareOctober 20, 2024 04:04
@kyracho
Copy link
ContributorAuthor

This is looking pretty good I think! I know this is still a draft so apologies if I'm jumping the gun with a review, but please add...

Thanks for the feedback! Added an image comparison test just now. I'll work on the "What's new" entry and the examples once I'm confident that the new changes are OK.

I didn't actually check the implementation, but does this also work with ticks on the right or the top?

Thanks! It didn’t handle ticks on the right or top before, but I've updated it to work with those ticks now.

@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch 3 times, most recently fromc074a15 toab27d59CompareOctober 20, 2024 04:31
@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch from06c5dff to249bb58CompareOctober 23, 2024 06:33
@github-actionsgithub-actionsbot added the Documentation: examplesfiles in galleries/examples labelOct 23, 2024
@kyrachokyracho marked this pull request as ready for reviewOctober 23, 2024 06:54
Copy link
Member

@timhoffmtimhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The fundamental implementation is already correct. The following are merely quality and style improvements.

Comment on lines 21 to 32
for j in range(2):
ax = axs[i][j]
ax.plot(np.arange(1., 0., -0.1) * 1000., np.arange(1., 0., -0.1))
ax.set_title(f'Title {i} {j}')
ax.set_xlabel(f'XLabel {i} {j}')
ax.set_ylabel(f'YLabel {i} {j}')
if (i == 0 and j == 1) or (i == 1 and j == 0):
if i == 0 and j == 1:
ax.xaxis.tick_top()
ax.set_xticks(np.linspace(0, 1000, 5))
ax.set_xticklabels([250 * n for n in range(5)])
ax.xaxis.set_tick_params(rotation=55, rotation_mode='xtick')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I agree that the example is a bit messy and could be improved, but it's largly orthogonal to the tick rotation topic. While one can do small additional improvements along the way, there's a couple of aspects I'd have to comment on.

I suggest to keep the change for this PR to the minimalax.tick_params(axis='x', rotation=55, rotation_mode='xtick'). If you are interested in improving the example, I'm happy to discuss that separately.

Copy link
ContributorAuthor

@kyrachokyrachoDec 5, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

TYSM for explaining so clearly, and for your hard work to help me contribute. I really appreciate it! 🩵

A few questions:

There seems to be an issue with

ax.tick_params(axis='x',rotation=55,rotation_mode='xtick')

It leads to

AttributeError: Line2D.set() got an unexpected keyword argument 'ion_mode'

Tracing to

classTick(martist.Artist):                   ⋮def__init__(.**kwargs):                   ⋮grid_kw= {k[5:]:vfork,vinkwargs.items()}

The fix I came up with is

grid_kw= {k[5:]:vfork,vinkwargs.items()ifk!="rotation_mode"}

to filter outrotation_mode and prevention_mode from being passed to theLine2D object.

I'm not sure if it would be better to apply it separately, to the__init__ method, though?

ax.tick_params(axis='x',rotation=55,rotation_mode='xtick')

seems to applyrotation_mode to only the first tick on the axis. Is there a delayed creation of the ticks at render time? so therotation_mode isn't being applied to all the labels?

I've tried using

ax.set_xticks(ax.get_xticks())ax.tick_params(axis='x',rotation=55,rotation_mode='xtick')

which seems to create the ticks before settingtick_params, but I'm not sure if it's a good solution?

@timhoffm
Copy link
Member

@kyracho gentle ping. Do you plan to continue with this?

kyracho reacted with heart emoji

@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch 6 times, most recently fromfcd99fa toef26713CompareDecember 5, 2024 12:56
@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch 3 times, most recently from8e00cc3 to1466f04CompareDecember 5, 2024 13:31
Copy link
Member

@timhoffmtimhoffm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This is good, apart from mixing the kw translation bugfix into the new feature.

Comment on lines 1098 to 1116
kwtrans = {}
for oldkey, newkey in keymap.items():
if newkey in kw_:
if is_x_axis and newkey == 'label1On':
kwtrans['labelbottom'] = kw_.pop(newkey)
elif is_x_axis and newkey == 'tick1On':
kwtrans['bottom'] = kw_.pop(newkey)
elif is_x_axis and newkey == 'label2On':
kwtrans['labeltop'] = kw_.pop(newkey)
elif is_x_axis and newkey == 'tick2On':
kwtrans['top'] = kw_.pop(newkey)
else:
kwtrans[oldkey] = kw_.pop(newkey)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'd like to have the bugfix separated from the rotation feature. Either as two commits in this PR, or (slightly perferred) as two separate PRs.

kyracho reacted with heart emoji
@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch 3 times, most recently fromd08f106 tob670278CompareDecember 7, 2024 03:25
@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch from0a30c7e to6207976CompareDecember 12, 2024 02:20
@kyrachokyrachoforce-pushed thepositioning_for_rotated_labels branch from09c58e5 to98778bbCompareDecember 13, 2024 04:57
@kyrachokyracho requested a review fromQuLogicJanuary 8, 2025 23:22
@timhoffmtimhoffm added this to thev3.11.0 milestoneJan 18, 2025
@kyracho
Copy link
ContributorAuthor

Hi@QuLogic , just checking in on this PR; whenever u have the time, I'd really appreciate your feedback.

Please let me know if there is anything I can improve.

Thank you!

@tacaswelltacaswell merged commit39c1d50 intomatplotlib:mainJan 31, 2025
39 checks passed
@tacaswell
Copy link
Member

Thank you@kyracho ! This is a pretty nice quality of life improvement.

kyracho reacted with heart emoji

@kyrachokyracho deleted the positioning_for_rotated_labels branchJanuary 31, 2025 20:36
timhoffm added a commit to timhoffm/matplotlib that referenced this pull requestFeb 7, 2025
Follow-up tomatplotlib#28968.The rotation_mode was only wired up half way, so that the parameter wasaccepted but did not have any effect.
timhoffm added a commit to timhoffm/matplotlib that referenced this pull requestFeb 8, 2025
Follow-up tomatplotlib#28968.The rotation_mode was only wired up half way, so that the parameter wasaccepted but did not have any effect.
QuLogic pushed a commit that referenced this pull requestFeb 11, 2025
* Fix tick_params() label rotation modeFollow-up to#28968.The rotation_mode was only wired up half way, so that the parameter wasaccepted but did not have any effect.* Update axis.pyi
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@timhoffmtimhoffmtimhoffm approved these changes

@scottshambaughscottshambaughAwaiting requested review from scottshambaugh

@QuLogicQuLogicAwaiting requested review from QuLogic

Assignees
No one assigned
Projects
None yet
Milestone
v3.11.0
Development

Successfully merging this pull request may close these issues.

[ENH]: Better positioning of rotated tick labels
6 participants
@kyracho@anntzer@timhoffm@tacaswell@QuLogic@scottshambaugh

[8]ページ先頭

©2009-2025 Movatter.jp