Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Added ability for the user to customize plot controls #94

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

kalebswartz7
Copy link

  • User can select location of 1D cuts (horizontal can be top / bottom,
    vertical can be left / right)
  • User can add a title to the plot
  • User can add subtitles for horizontal and vertical axes
  • User can specify extent labels for image

closes #90

- User can select location of 1D cuts (horizontal can be top / bottom,
vertical can be left / right)
- User can add a title to the plot
- User can add subtitles for horizontal and vertical axes
- User can specify extent labels for image
@mrakitin
Copy link
Member

@tacaswell, @danielballan, I'd love to hear your comments on this enhancement, which we worked on together with @kalebswartz7. Thanks!

@kalebswartz7
Copy link
Author

Code snippet to test functionality:

img = np.loadtxt('res_int_pr_se.dat')
img = img.reshape((294, 528))
fig = plt.figure()
cs = CrossSection(fig, vert_loc='right', horiz_loc='bottom', title='Example', horiz_label='horizontal', vert_label='vertical', extent_labels=[-50, 50, -50, 50])
cs.update_image(img)
plt.show()

Can replace / remove any of these parameters. Just need to read in a data file.

Copy link

@jrmlhermitte jrmlhermitte left a comment

Choose a reason for hiding this comment

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

Looks good!

I tried with:

import numpy as np
from xray_vision.backend.mpl.cross_section_2d import CrossSection
import matplotlib.pyplot as plt
plt.ion()

img = np.random.random((10,20))
fig = plt.figure()
cs = CrossSection(fig, vert_loc='right', horiz_loc='bottom', title='Example', horiz_label='horizontal', vert_label='vertical', extent_labels=[-50, 50, -50, 50])
cs.update_image(img)

img = np.random.random((10,20))
fig = plt.figure()
cs = CrossSection(fig)
cs.update_image(img)

I have a few comments. One main comment. I think the extent should be passed in update_img. I think this will simplify a lot of logic inside.

To get started, look for this line in code

self._init_artists(image, extent=extent)

and update things accordingly to get it working.

My feeling is that you will move all the extent logic into a self contained helper function and not have to worry about sharing or not sharing axes.

Also, right now, when I drag the image, the cross sections don't move. I think this will help with that.
If you decide to make a big change like this, i recommend naming this last commit to another branch so that you can easily go back if needed.

Anyway, thanks again for the contribution!
Also, in passing I noticed that the plots don't line up. I posted an issue here. Maybe you can try fixing that since while you're at it (I'm not sure if it is trivial or not though, I remember battling with these small details in the past quite a bit...)

label that describes the x axis of the vertical plot
horiz_label : str, optional
label that describes the x axis of the horizontal plot
extent_labels : list, optional

Choose a reason for hiding this comment

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

a few comments:

  1. should be list of str or int? (you typecast it later to int)
  2. Why not just call it extent to keep consistent with matplotlib:

extent : scalars (left, right, bottom, top), optional, default: None
The location, in data-coordinates, of the lower-left and upper-right corners. If None, the image is positioned such that the pixel centers fall on zero-based (row, column) indices.

  1. I would at least recommend to remove "label" in variable name as it might make it sound like it can be any string.
    These are just suggestions, feel free to disagree! :)

  2. Finally, I think this one might be a better API move: move this "extent" kwarg to the update_img method (i.e. we want to pass the extent to the function where we pass the image). This extent can potentially change with each new image, and so should come with the image. You could have it available in __init__ as well but i think that might to too much of a support nightmare. Let me know what you think.

Copy link
Author

Choose a reason for hiding this comment

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

  • Maksim and I discussed the extent name, we just thought that if it were extent only there could be some confusion as the actual extent is not set - the image just appears as so. This is because when using actual extent the image would not fill the entire subplot. I do agree to change the type from a list to scalars with a more fitting description.

  • To go along with that we tried using the self.init_artists function to pass in extent but we encountered the error described above. Ideally extent would actually be set but we couldn't figure out how to do so. If this were figured out the extent_labels name could just simply be extent and it would make much more sense.

  • I will be sure to check out moving the extent kwarg to the update_img function and look into aligning the plot lines - thanks for the feedback!

horiz_label : str, optional
label that describes the x axis of the horizontal plot
extent_labels : list, optional
[x value initial, x value final, y value initial, y value final]

Choose a reason for hiding this comment

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

I would also call it "left, right, bottom top" since it's decsribing the image. But that's mainly because I'm used to matplotlib, so again more a suggestion!

Copy link
Author

Choose a reason for hiding this comment

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

  • This definitely makes sense!

self.title = title
self.vert_label = vert_label
self.horiz_label = horiz_label
self.extent_labels = extent_labels

Choose a reason for hiding this comment

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

With my suggestion on extent, this will move to update_img and thus not need to be an instance attribute.

int(self.extent_labels[1]), 5)
self.y_tick_values = np.linspace(int(extent_labels[2]),
int(extent_labels[3]), 5)
if vert_loc is None or vert_loc is not 'right':

Choose a reason for hiding this comment

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

i would move this lower and raise a ValueError:

if vert_loc is None:
    vert_loc = left
if vert_loc not in {'right', 'left'}:
    raise ValueError(f"Error, {vert_loc} not 'left' or 'right'")

it's longer but I think it's more readable. Also, if the default value is not understood, its best to give the user feedback they've done something wrong (i.e. maybe they thought left=0 and right = 1 but not they're always getting left)

Copy link
Author

Choose a reason for hiding this comment

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

  • I will implement this change

kwargs_vert = {'position': self.vert_loc, 'size': .5, 'pad': 0.1}
kwargs_horiz = {'position': self.horiz_loc, 'size': .5}
if self.extent_labels is None:
kwargs_vert['sharey'] = self._im_ax

Choose a reason for hiding this comment

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

why are you only sharing when there are extent labels?
I'm not very familiar, but I tried moving the image with the mouse without extent_labels and the cross section follows.
However, it does not for the image. Perhaps we should always share, and make sure the image extent is the same as the cross section's limits.

(more comments below suggesting what to do )

Copy link
Author

Choose a reason for hiding this comment

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

  • Initially there was no reason to get rid of the shared axes, but when they are shared the extent labels appear on the image rather than the vertical and horizontal cuts.

Copy link
Member

Choose a reason for hiding this comment

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

Interesting. The code seems to be right since it applies the labels/ticks to the correct axes, self._ax_h and self._ax_v. Can it be a matplotlib bug? @tacaswell, thoughts?

return "X: {x:d} Y: {y:d} I: {i:.2f}".format(x=col, y=row, i=z)
if self.extent_labels is not None:
return "X: {x:g} Y: {y:g} I: {i:g}".format(
x=col / im_shape[1] * (self.extent_labels[1] -

Choose a reason for hiding this comment

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

I think if you set the image extent you won't need this anymore
you can do this in (look for this line in code)

self._init_artists(image, extent=extent)

and update things accordingly to get it working.

@@ -676,3 +774,12 @@ def autoscale_horizontal(self, enable):
@auto_redraw
def autoscale_vertical(self, enable):
self._ax_v.autoscale(enable=False)


def _swap_sides(key, enum):

Choose a reason for hiding this comment

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

can you add a comment explaining what this is doing and why?

Copy link
Author

Choose a reason for hiding this comment

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

  • I will add a comment!

Copy link
Member

Choose a reason for hiding this comment

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

This is a helper function to easily swap the sides, e.g. 'left' -> 'right' and vice versa. In case the supplied value key is not in keys of enum, the default value from the enum is used (default is the one which has the True value).

@kalebswartz7, please create a docstring explaining this and the arguments to the function. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ENH: titles on image plots
3 participants