1
votes

Researching this, I have found answers which involved using an iterator and a loop to plot n sets of data.

Is there a way to do it without using a loop?

I have an array odata which contains n columns. The first column is the abscissa. I want to plot the rest.

I have a line of code like this:

plt.plot(odata[:,0],odata[:,1:],'-')

This does the plot, But I want to add my own colors and labels. How?

1
Why do you not want to use a loop? Looping is a very basic and common programming idea; there's no reason to avoid it when it is the correct tool for the job.Brian A. Henning
Are you saying it can't be done without looping?Mannix
In the strictest sense, yes--it cannot be done without looping. A loop is happening, whether you write the loop yourself in the Python code, or you use a single-line Python range syntax (in which case Python is doing the loop for you behind the scenes). While it may be possible to write code to do what you want without any obvious loops, there is a loop happening when it runs.Brian A. Henning
You are correct that no loops are required. You just need to have a sequence of labels and colors in the correct order. Matplotlib will do all the looping for you pretty seamlessly.Mad Physicist

1 Answers

0
votes

You can access the Line2D objects that are created using the return value of plt.plot, and set the legend directly based on that list:

labels = ['a', 'b', 'c']
lines = plt.plot(odata[:, 0], odata[:, 1:], '-')
plt.legend(lines, labels)

The number of labels and lines does not necessarily have to match. If there are fewer lines, some of the labels will be unused. If there are fewer labels, some of the lines will be unlabeled. Here is the legend guide in the documentation.

To seamlessly change the order of the colors, you would need to set the cycler in the global configuration via matplotlib.rc as in this example from the docs, or use the object-oriented API to do your plotting. Then you can use set_prop_cycle on your individual axes without messing around with the global settings.

Here are three approaches for setting the color cycler in order of increasing personal preference. Note that I am only showing how to set the color here, but you can also control the sequence of line styles and probably other attributes as well:

  1. Set the global configuration:

    import matplotlib as mpl
    from matplotlib import cycler
    from matplotlib import pyplot as plt
    
    labels = ['a', 'b', 'c']
    colors = ['r', 'g', 'b']
    
    mpl.rc('axes', prop_cycle=cycler('color', ['r', 'g', 'b', 'y']))
    
    lines = plt.plot(odata[:, 0], odata[:, 1:], '-')
    plt.legend(lines, labels)
    
  2. Set the global configuration, but using the rc_context context manager to make the changes effectively local to your plot:

    import matplotlib as mpl
    from matplotlib import cycler,rc_context
    from matplotlib import pyplot as plt
    
    labels = ['a', 'b', 'c']
    colors = ['r', 'g', 'b']
    
    with rc_context(rc={'axes.prop_cycle': cycler('color', ['r', 'g', 'b', 'y'])}):
        lines = plt.plot(odata[:, 0], odata[:, 1:], '-')
        plt.legend(lines, labels)
    
  3. Set up the plot using the object-oriented API to begin with, and apply changes only to the Axes that you actually want to modify:

    from matplotlib import pyplot as plt
    
    labels = ['a', 'b', 'c']
    colors = ['r', 'g', 'b']
    
    fig, ax = plt.subplots()
    ax.set_prop_cycle('color', colors)
    ax.plot(odata[:, 0], odata[:, 1:], '-')
    ax.legend(labels)
    

I would recommend the object-oriented API as a general rule, especially within standalone scripts because it offers much greater flexibility, and also clarity in terms of knowing exactly what objects will be operated on.