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

[ENH] Support for Multi-Color Line Legends in Plots #28304

Open
@nikosarcevic

Description

@nikosarcevic

Need

This enhancement proposes adding native support for multi-color lines in the legend of line (and other styles!) plots in Matplotlib. This feature will allow users to represent data series with gradients or multiple colors more intuitively within the plot legends.

Proposed solution

Hello, awesome matplotlib people!

Why This Enhancement is Needed

  • Improved Data Visualization: Multi-color lines in legends can significantly enhance the readability and interpretability of plots, especially in cases where data series represent a range of values or a transition over time.
  • Consistency: Currently, users need to implement custom handlers for multi-color lines, which can be cumbersome and inconsistent. Native support will standardize the implementation.
  • User Demand: As data visualizations become more complex and integral to analysis, the demand for more advanced and intuitive plotting features increases. This feature aligns with modern data visualization needs.

Benefits

  • Enhanced Clarity: Users can visually match plot lines with legend entries more easily when colors in the legend reflect the actual colors used in the plot.
  • Time-Saving: Eliminates the need for users to write and maintain custom legend handlers for multi-color lines.
  • Professional Presentation: Provides a more polished and professional look to data visualizations, which is crucial for presentations and publications.

Proposed Implementation

Add support in the Legend class for a new handler that can process and display multi-color lines.
This handler will generate a line segment with a gradient or series of colors, consistent with the corresponding plot line.

My current implementation:

import matplotlib.pyplot as pltimport numpy as npfrom matplotlib.collections import LineCollectionfrom matplotlib.legend_handler import HandlerLineCollectionfrom matplotlib.colors import Normalizeimport cmasher as cmrclass HandlerColorLineCollection(HandlerLineCollection):    def __init__(self, cmap, **kwargs):        self.cmap = cmap        super().__init__(**kwargs)        def create_artists(self, legend, artist, xdescent, ydescent, width, height, fontsize, trans):        x = np.linspace(0, width, self.get_numpoints(legend) + 1)        y = np.zeros(self.get_numpoints(legend) + 1) + height / 2. - ydescent        points = np.array([x, y]).T.reshape(-1, 1, 2)        segments = np.concatenate([points[:-1], points[1:]], axis=1)        lc = LineCollection(segments, cmap=self.cmap, transform=trans)        lc.set_array(x)        lc.set_linewidth(artist.get_linewidth())        return [lc]def add_normalized_line_collection(ax, cmap, linewidth=3, linestyle='-'):    norm = Normalize(vmin=0., vmax=1.)    t = np.linspace(0, 1, 100)  # Smooth gradient    lc = LineCollection([np.column_stack([t, t * 0])], cmap=cmap, norm=norm, linewidth=linewidth, linestyle=linestyle)    lc.set_array(np.linspace(0., 1, len(t)))  # Ensure this spans 0 to 1 for correct normalization    ax.add_collection(lc)  # Add the LineCollection to the axis    return lc# Sample datax_data = np.logspace(1, 3, 50)y_data = np.random.rand(3, len(x_data))fig, ax = plt.subplots(figsize=(8, 6))colors = cmr.take_cmap_colors('cmr.rainforest', 3, cmap_range=(0.15, 0.85), return_fmt='hex')for i in range(y_data.shape[0]):    ax.plot(x_data, y_data[i], color=colors[i], lw=3)        ax.set_xlabel('$x$', fontsize=18)    ax.set_ylabel('$y$', fontsize=18)# Create color lines for legendcolor_line = add_normalized_line_collection(ax, cmap="cmr.rainforest", linewidth=4)# Existing legend handles and labelshandles, labels = ax.get_legend_handles_labels()handles.append(color_line)labels.append("Colormap-based Line")ax.legend(handles, labels, handler_map={color_line: HandlerColorLineCollection(cmap="cmr.rainforest", numpoints=30)}, loc="upper right", frameon=True, fontsize=15)plt.show()
Screenshot 2024-05-26 at 17 40 26

Proposed usage

import matplotlib.pyplot as pltimport numpy as npimport cmasher as cmr# Sample datax_data = np.logspace(1, 3, 50)y_data = np.random.rand(3, len(x_data))fig, ax = plt.subplots(figsize=(8, 6))colors = cmr.take_cmap_colors('cmr.rainforest', 3, cmap_range=(0.15, 0.85), return_fmt='hex')for i in range(y_data.shape[0]):    ax.plot(x_data, y_data[i], color=colors[i], lw=3)        ax.set_xlabel('$x$', fontsize=18)    ax.set_ylabel('$y$', fontsize=18)# New API for colormap-based lines in legendax.legend(use_colormap=True, loc="upper right", frameon=True, fontsize=15, new_arg='cmr.rainforest', )plt.show()

Please note that it would be beneficial to allow passing either a colormap or a list of colors (in HEX) to this new argument (new_arg) in the legend. Ideally, the legend object should be able to internally determine the colors used in the plot lines, making the process seamless and intuitive for the user.

I am alsoincluding a version from a colleague.

Many thanks!
Niko

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


      [8]ページ先頭

      ©2009-2025 Movatter.jp