Skip to content
New issue

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

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Timeseries plot style #465

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open

Timeseries plot style #465

wants to merge 24 commits into from

Conversation

FrejaTerpPetersen
Copy link

@FrejaTerpPetersen FrejaTerpPetersen commented Nov 6, 2024

An update to the comparer plotter such that it takes a style and a color input. I wanted to also allow for color input, since this is actually the main reason why I started the issue #463: I want to use my own colors to match my other plots. The style input is just a bonus from my point of view :)

Design decisions:

  • The user can only pass one of the two; either color OR style
  • If none are passed, the default colors are used.
  • Inputs can be passed as list of strings or as a single string. If a single string is passed but more than one model result is in the comparer, an error is raised. If len(list) < num_models an error is also raised.
  • If len(color) > num_models: the first color is used for the observations. I am unsure whether this is the best way to do it, since there might be cases, where I just have a large list of colors that I pass to all of my plots regardless of the number of models... On the other hand, allowing the user to choose the observation colors is also useful in case of duplicate colors (default obs color is black, and maybe I want one of the lines to be black too?)

Example 1: giving a color input

# Given a comparer:
cmp = create_comparer()
# Pass a color input to the plot.timeseries() method
ax = cmp.plot.timeseries(color=["red", "blue"])
plt.show()

This code yields the following plot:
image

Example 2: also specifying the color of the observation points
Above, the default color of the observations is black. If we want them to be e.g. green instead, we pass it as the first color.

# Pass a color input to the plot.timeseries() method
ax = cmp.plot.timeseries(color=["green","red", "blue"])
plt.show()

This yields the following plot:
image

Example 3: giving a style input
We can also pass a style input instead

# Pass a color input to the plot.timeseries() method
ax = cmp.plot.timeseries(style=["r-.", "b--"])
plt.show()

image

@ecomodeller
Copy link
Member

@FrejaTerpPetersen for the benefit of the interested reader... could you please include some sample code and screenshots of the new functionality in this description above. Visuals are easy to grasp, when browsing around.

@FrejaTerpPetersen
Copy link
Author

Sure thing - I updated the description

else:
if color is None:
color = MOD_COLORS
mod.plot(ax=ax, color=color[j])

ax.scatter(
cmp.time,
cmp.data[cmp._obs_name].values,
marker=".",
Copy link
Member

Choose a reason for hiding this comment

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

style does not affect the observations, is this the intended behaviour?

Copy link
Author

@FrejaTerpPetersen FrejaTerpPetersen Mar 12, 2025

Choose a reason for hiding this comment

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

Yes, observations can't have their style changed now. THis is a design choice, I guess? We could allow the user to input style for obs? Might lead to confusion, however, since I guess the user is pretty happy with a dot for the obs

Copy link
Member

Choose a reason for hiding this comment

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

I see the color can be changed. But not the marker.

# Color for observations:
obs_color = cmp.data[cmp._obs_name].attrs["color"]

# if color is None and style is None: # Use default values for colors
Copy link
Member

Choose a reason for hiding this comment

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

remove unused code

Copy link
Member

@jsmariegaard jsmariegaard left a comment

Choose a reason for hiding this comment

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

Great work!

I would like to see a few changes:

  • please change _check_kwarg_and_convert_to_list to only check for either style or color and rename to _check_arg_length_match_nmodels(arg, arg_name, n_mod) or to something with _parse (as it returns the same argument again)
  • move the function out of _misc.py and to top of _comparer_plotter.py (it is only used in this module)
  • I think we should allow either lengths n_mod and n_mod+1 only (i.e. also issue exception if length is too long)
  • It seems that the color and style args work a little different if you want to change the obs apperance also. Is it correct that you cannot change the style of the observation.
  • I guess the style and color arguments only applied to matplotlib backend and not plotly. If that is the case - it should be clear in the docstring. Better: add it to plotly backend also.
  • currently all kwargs are accepted, e.g. cmp.plot.timeseries(assdsddsdas="Reds") does not give me an error message. It should. It is not strictly part of this PR, but as this function is now "open", we should fix it.
  • I have added a short notebook with examples - maybe you could expand it a little bit?

@jsmariegaard
Copy link
Member

closes #463

@jsmariegaard jsmariegaard linked an issue Dec 18, 2024 that may be closed by this pull request
@ecomodeller
Copy link
Member

@FrejaTerpPetersen What is the status on this PR?

@FrejaTerpPetersen
Copy link
Author

@ecomodeller I think it is ready for merge, unless you have further comments.

I updated according to Jespers comments:

  • please change _check_kwarg_and_convert_to_list to only check for either style or color and rename to _check_arg_length_match_nmodels(arg, arg_name, n_mod) or to something with _parse (as it returns the same argument again)
    ->I changed the function to your first suggestion. Not familiar with '_parse' - what would that mean?
  • move the function out of _misc.py and to top of _comparer_plotter.py (it is only used in this module)
    ->Done
  • I think we should allow either lengths n_mod and n_mod+1 only (i.e. also issue exception if length is too long)
    -> Hmmm, my reason for allowing more colors is that the user of the function might just have some generic list of colors from a theme that they want to input without subsetting. But maybe that is an unusual use-case?
  • I guess the style and color arguments only applied to matplotlib backend and not plotly. If that is the case - it should be clear in the docstring. Better: add it to plotly backend also.
    -> I changed docstring - not familiar with plotly so can't quickly do this.
  • currently all kwargs are accepted, e.g. cmp.plot.timeseries(assdsddsdas="Reds") does not give me an error message. It should. It is not strictly part of this PR, but as this function is now "open", we should fix it.
    -> Hmm, not sure I understand exactly ...

@ecomodeller, @jsmariegaard - do you want to review before merging?

@jsmariegaard
Copy link
Member

Yes, either @ecomodeller or I will merge after review. Thanks

if isinstance(arg, str):
# If arg is str, convert to list (for looping)
arg = [arg]
if arg is not None and len(arg) < n_mod:
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't account for the case where the user passes more arguments than n_mod. This should not be silently ignored.

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

Successfully merging this pull request may close these issues.

Passing matplotlib arguments to plot.timeseries()
3 participants