简体   繁体   中英

Plotting and color coding multiple y-axes

This is my first attempt using Matplotlib and I am in need of some guidance. I am trying to generate plot with 4 y-axes, two on the left and two on the right with shared x axis. Here's my dataset on shared dropbox folder

import pandas as pd
%matplotlib inline

url ='http://dropproxy.com/f/D34'

df= pd.read_csv(url, index_col=0, parse_dates=[0])
df.plot()

This is what the simple pandas plot looks like:

在此处输入图片说明

I would like to plot this similar to the example below, with TMAX and TMIN on primary y-axis (on same scale). 在此处输入图片说明

My attempt:

There's one example I found on the the matplotlib listserv ..I am trying to adapt it to my data but something is not working right...Here's the script.

# multiple_yaxes_with_spines.py

# This is a template Python program for creating plots (line graphs) with 2, 3,
# or 4 y-axes.  (A template program is one that you can readily modify to meet
# your needs).  Almost all user-modifiable code is in Section 2.  For most
# purposes, it should not be necessary to modify anything else.

# Dr. Phillip M. Feldman,  27 Oct, 2009

# Acknowledgment: This program is based on code written by Jae-Joon Lee,
# URL= http://matplotlib.svn.sourceforge.net/viewvc/matplotlib/trunk/matplotlib/
# examples/pylab_examples/multiple_yaxis_with_spines.py?revision=7908&view=markup


# Section 1: Import modules, define functions, and allocate storage.

import matplotlib.pyplot as plt
from numpy import *

def make_patch_spines_invisible(ax):
    ax.set_frame_on(True)
    ax.patch.set_visible(False)
    for sp in ax.spines.itervalues():
        sp.set_visible(False)

def make_spine_invisible(ax, direction):
    if direction in ["right", "left"]:
        ax.yaxis.set_ticks_position(direction)
        ax.yaxis.set_label_position(direction)
    elif direction in ["top", "bottom"]:
        ax.xaxis.set_ticks_position(direction)
        ax.xaxis.set_label_position(direction)
    else:
        raise ValueError("Unknown Direction : %s" % (direction,))

    ax.spines[direction].set_visible(True)

# Create list to store dependent variable data:
y= [0, 0, 0, 0, 0]


# Section 2: Define names of variables and the data to be plotted.

# `labels` stores the names of the independent and dependent variables).  The
# first (zeroth) item in the list is the x-axis label; remaining labels are the
# first y-axis label, second y-axis label, and so on.  There must be at least
# two dependent variables and not more than four.

labels= ['Date', 'Maximum Temperature', 'Solar Radiation',
  'Rainfall', 'Minimum Temperature']

# Plug in your data here, or code equations to generate the data if you wish to
# plot mathematical functions.  x stores values of the independent variable;
# y[1], y[2], ... store values of the dependent variable.  (y[0] is not used).
# All of these objects should be NumPy arrays.

# If you are plotting mathematical functions, you will probably want an array of
# uniformly spaced values of x; such an array can be created using the
# `linspace` function.  For example, to define x as an array of 51 values
# uniformly spaced between 0 and 2, use the following command:

#    x= linspace(0., 2., 51)

# Here is an example of 6 experimentally measured y1-values:

#    y[1]= array( [3, 2.5, 7.3e4, 4, 8, 3] )

# Note that the above statement requires both parentheses and square brackets.

# With a bit of work, one could make this program read the data from a text file
# or Excel worksheet.

# Independent variable:
x = df.index
# First dependent variable:
y[1]= df['TMAX']
# Second dependent variable:
y[2]= df['RAD']
y[3]= df['RAIN']
y[4]= df['TMIN']

# Set line colors here; each color can be specified using a single-letter color
# identifier ('b'= blue, 'r'= red, 'g'= green, 'k'= black, 'y'= yellow,
# 'm'= magenta, 'y'= yellow), an RGB tuple, or almost any standard English color
# name written without spaces, e.g., 'darkred'.  The first element of this list
# is not used.
colors= [' ', '#C82121', '#E48E3C', '#4F88BE', '#CF5ADC']

# Set the line width here.  linewidth=2 is recommended.
linewidth= 2


# Section 3: Generate the plot.

N_dependents= len(labels) - 1
if N_dependents > 4: raise Exception, \
   'This code currently handles a maximum of four independent variables.'

# Open a new figure window, setting the size to 10-by-7 inches and the facecolor
# to white:
fig= plt.figure(figsize=(16,9), dpi=120, facecolor=[1,1,1])

host= fig.add_subplot(111)

host.set_xlabel(labels[0])

# Use twinx() to create extra axes for all dependent variables except the first
# (we get the first as part of the host axes).  The first element of y_axis is
# not used.
y_axis= (N_dependents+2) * [0]
y_axis[1]= host
for i in range(2,len(labels)+1): y_axis[i]= host.twinx()

if N_dependents >= 3:
   # The following statement positions the third y-axis to the right of the
   # frame, with the space between the frame and the axis controlled by the
   # numerical argument to set_position; this value should be between 1.10 and
   # 1.2.
   y_axis[3].spines["right"].set_position(("axes", 1.15))
   make_patch_spines_invisible(y_axis[3])
   make_spine_invisible(y_axis[3], "right")
   plt.subplots_adjust(left=0.0, right=0.8)

if N_dependents >= 4:
   # The following statement positions the fourth y-axis to the left of the
   # frame, with the space between the frame and the axis controlled by the
   # numerical argument to set_position; this value should be between 1.10 and
   # 1.2.
   y_axis[4].spines["left"].set_position(("axes", -0.15))
   make_patch_spines_invisible(y_axis[4])
   make_spine_invisible(y_axis[4], "left")
   plt.subplots_adjust(left=0.2, right=0.8)

p= (N_dependents+1) * [0]

# Plot the curves:
for i in range(1,N_dependents+1):
   p[i], = y_axis[i].plot(x, y[i], colors[i],
     linewidth=linewidth, label=labels[i])

# Set axis limits.  Use ceil() to force upper y-axis limits to be round numbers.
host.set_xlim(x.min(), x.max())

host.set_xlabel(labels[0], size=16)

for i in range(1,N_dependents+1):
   y_axis[i].set_ylim(0.0, ceil(y[i].max()))
   y_axis[i].set_ylabel(labels[i], size=16)
   y_axis[i].yaxis.label.set_color(colors[i])

   for sp in y_axis[i].spines.itervalues():
     sp.set_color(colors[i])

   for obj in y_axis[i].yaxis.get_ticklines():
      # `obj` is a matplotlib.lines.Line2D instance
      obj.set_color(colors[i])
      obj.set_markeredgewidth(3)

   for obj in y_axis[i].yaxis.get_ticklabels():
      obj.set_color(colors[i])
      obj.set_size(12)
      obj.set_weight(600)

# To enable the legend, uncomment the following two lines:
lines= p[1:]
host.legend(lines, [l.get_label() for l in lines])

plt.draw(); plt.show()

And the output

在此处输入图片说明

How can I put the scale on max and min temp on a same scale? Also, how can I get rid of second y-axis with black color, scaled from 0 to 10?

Is there a simpler way to achieve this?

How can I put the scale on max and min temp on a same scale?

Plot them in the same axes.

Also, how can I get rid of second y-axis with black color, scaled from 0 to 10?

Do not create that axes.

You want to plot four variables, two of them can go in the same subplot so you only need three subplots. But you are creating five of them?

Step by step

Keep in mind: different y scales <-> different subplots sharing x-axis.

Two variables with a common scale (left), two variables with independent scales (right).

  1. Create the primary subplot, let's call it ax1 . Plot everything you want in it, in this case TMIN and TMAX as stated in your question.
  2. Create a twin subplot sharing x axis twinx(ax=ax1) . Plot the third variable, say RAIN.
  3. Create another twin subplot twinx(ax=ax1) . Plot the fourth variable 'RAD'.
  4. Adjust colors, labels, spine positions... to your heart's content.

Unsolicited advice: do not try to fix code you don't understand.

Variation of the original plot showing how you can plot variables on multiple axes

import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

url ='http://dropproxy.com/f/D34'

df= pd.read_csv(url, index_col=0, parse_dates=[0])

fig = plt.figure()

ax = fig.add_subplot(111) # Primary y
ax2 = ax.twinx() # Secondary y

# Plot variables
ax.plot(df.index, df['TMAX'], color='red')
ax.plot(df.index, df['TMIN'], color='green')
ax2.plot(df.index, df['RAIN'], color='orange')
ax2.plot(df.index, df['RAD'],  color='yellow')

# Custom ylimit
ax.set_ylim(0,50)

# Custom x axis date formats
import matplotlib.dates as mdates
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))

I modified @bishopo's suggestions to generate what I wanted, however, the plot still needs some tweaking with font sizes for axes label.

Here's what I have done so far.

import pandas as pd
%matplotlib inline

url ='http://dropproxy.com/f/D34'

df= pd.read_csv(url, index_col=0, parse_dates=[0])

from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as AA
import matplotlib.pyplot as plt





if 1:
    # Set the figure size, dpi, and background color
    fig = plt.figure(1, (16,9),dpi =300, facecolor = 'W',edgecolor ='k')


    # Update the tick label size to 12
    plt.rcParams.update({'font.size': 12})
    host = host_subplot(111, axes_class=AA.Axes)
    plt.subplots_adjust(right=0.75)

    par1 = host.twinx()
    par2 = host.twinx()
    par3 = host.twinx()

    offset = 60

    new_fixed_axis = par2.get_grid_helper().new_fixed_axis
    new_fixed_axis1 = host.get_grid_helper().new_fixed_axis
    par2.axis["right"] = new_fixed_axis(loc="right",
                                        axes=par2,
                                        offset=(offset, 0))
    par3.axis["left"] = new_fixed_axis1(loc="left",
                                        axes=par3,
                                        offset=(-offset, 0))

    par2.axis["right"].toggle(all=True)
    par3.axis["left"].toggle(all=True)
    par3.axis["right"].set_visible(False)


    # Set limit on both y-axes
    host.set_ylim(-30, 50)
    par3.set_ylim(-30,50)

    host.set_xlabel("Date")
    host.set_ylabel("Minimum Temperature ($^\circ$C)")
    par1.set_ylabel("Solar Radiation (W$m^{-2}$)")
    par2.set_ylabel("Rainfall (mm)")
    par3.set_ylabel('Maximum Temperature ($^\circ$C)')


    p1, = host.plot(df.index,df['TMIN'], 'm,')
    p2, = par1.plot(df.index, df.RAD, color ='#EF9600', linestyle ='--')
    p3, = par2.plot(df.index, df.RAIN, '#09BEEF')
    p4, = par3.plot(df.index, df['TMAX'], '#FF8284')

    par1.set_ylim(0, 36)
    par2.set_ylim(0, 360)

    host.legend()


    host.axis["left"].label.set_color(p1.get_color())
    par1.axis["right"].label.set_color(p2.get_color())
    par2.axis["right"].label.set_color(p3.get_color())
    par3.axis["left"].label.set_color(p4.get_color())



    tkw = dict(size=5, width=1.5)
    host.tick_params(axis='y', colors=p1.get_color(), **tkw)
    par1.tick_params(axis='y', colors=p2.get_color(), **tkw)
    par2.tick_params(axis='y', colors=p3.get_color(), **tkw)
    par3.tick_params(axis='y', colors=p4.get_color(), **tkw)
    host.tick_params(axis='x', **tkw)



    par1.axis["right"].label.set_fontsize(16)
    par2.axis["right"].label.set_fontsize(16)
    par3.axis["left"].label.set_fontsize(16)
    host.axis["bottom"].label.set_fontsize(16)
    host.axis["left"].label.set_fontsize(16)


    plt.figtext(.5,.92,'Weather Data', fontsize=22, ha='center')
    plt.draw()
    plt.show()

    fig.savefig("Test1.png") 

The output 在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM