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

Timeseries plot style #465

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

Timeseries plot style #465

wants to merge 17 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?

if backend == "matplotlib":
fig, ax = _get_fig_ax(ax, figsize)
for j in range(cmp.n_models):
key = cmp.mod_names[j]
mod = cmp.raw_mod_data[key]._values_as_series
mod.plot(ax=ax, color=MOD_COLORS[j])
if style is not None:
mod.plot(ax=ax, style=style[j])
Copy link
Member

Choose a reason for hiding this comment

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

I suggest to add a check (outside the loop) that the length of the style list is the same as the number of models (or models+1 obs, see comment below).

# 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
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.

Passing matplotlib arguments to plot.timeseries()
3 participants