Reputation: 177
Working on a personal project that draws two lines, each dashed (ls='--') for the first two x-axis markings, then it is a solid line...thinking about writing a tutorial since I've found no information on this. Anyhow, the trick I'm stumped at, is to figure how many points are used to make the line for the first two x-axis markings, so I can properly turn off the solid line up to that point. I'm using the Line.set_dashes()
method to turn off the solid line, and I'm making an individual (non-connected) copy and setting the linestyle to dash. This causes the lines to be drawn on top of each other, and the solid to take precedence when ON. However, the Line.set_dashes()
takes "points" as arguments. I figured out where, but as you see, the second line has different angles, thus length, so this point is further along the line. Maybe there's a better way to set the line to two styles?
Here is an example plot --> https://flic.kr/p/rin6Z5
r = getPostData(wall)
if len(newTimes) < LIMIT:
LIMIT = len(newTimes)
yLim = int(round(max(r['Likes'].max(), r['Shares'].max()) * 1.2))
xLim = LIMIT
L1A = plt.Line2D(range(LIMIT), r['Likes'], color='b', ls='--')
L1B = plt.Line2D(range(LIMIT), r['Likes'], label='Likes', color='b')
L2A = plt.Line2D(range(LIMIT), r['Shares'], color='r', ls='--')
L2B = plt.Line2D(range(LIMIT), r['Shares'], label='Shares', color='r')
LNull = plt.Line2D(range(LIMIT), r['Shares'], ls='--', label='Recent Data\n(Early collection)', color='k')
dashes = [1,84,7000,1]
dashesNull=[1,7000]
fig = plt.figure()
ax = fig.add_subplot(111, ylim=(0,yLim), xlim=(0,xLim))
ax.add_line(L1A)
ax.add_line(L1B)
ax.add_line(L2A)
ax.add_line(L2B)
ax.add_line(LNull)
ax.legend(bbox_to_anchor=(1.5,1))
L1B.set_dashes(dashes)
L2B.set_dashes(dashes)
LNull.set_dashes(dashesNull)
Upvotes: 0
Views: 611
Reputation: 177
i thought so too, anyhow, the resulting code is now...
def splitLine(ax, x, y, splitNum, style1, style2):
'''Creates a two styled line given;
ax = an axis
x = an array of x coordinates for 2D Line
y = an array of y coordinates for 2D Line
splitNum = index number to split Line by x tick
style1 = dictionary for left part of Line
style2 = dictionary for right part of Line
'''
split = x[splitNum]
low_mask = x <= split
upper_mask = x >= split
lower, = ax.plot(x[low_mask], y[low_mask], **style1)
upper, = ax.plot(x[upper_mask], y[upper_mask], **style2)
return lower, upper
r = getPostData(wall)
earlyLike = {'color': 'r', 'lw': 1, 'ls': '--'}
agedLike = {'color': 'r', 'lw': 2, 'ls': '-', 'label': 'Likes'}
earlyShare = {'color': 'b', 'lw': 1, 'ls': '--'}
agedShare = {'color': 'b', 'lw': 2, 'ls': '-', 'label': 'Shares'}
fig, ax = plt.subplots()
splitLine(ax, np.array(range(LIMIT)), np.array(r['Likes']), 1, earlyLike, agedLike)
splitLine(ax, np.array(range(LIMIT)), np.array(r['Shares']), 1, earlyShare, agedShare)
Upvotes: 0
Reputation: 87356
I would write your self a helper function, something like:
import numpy as np
import matplotlib.pyplot as plt
def split_plot(ax, x, y, low, high, inner_style, outer_style):
"""
Split styling of line based on the x-value
Parameters
----------
x, y : ndarray
Data, must be same length
low, high : float
The low and high threshold values, points for `low < x < high` are
styled using `inner_style` and points for `x < low or x > high` are
styled using `outer_style`
inner_style, outer_style : dict
Dictionary of styles that can be passed to `ax.plot`
Returns
-------
lower, mid, upper : Line2D
The artists for the lower, midddle, and upper ranges
vline_low, vline_hi : Line2D
Vertical lines at the thresholds
hspan : Patch
Patch over middle region
"""
low_mask = x < low
high_mask = x > high
mid_mask = ~np.logical_or(low_mask, high_mask)
low_mask[1:] |= low_mask[:-1]
high_mask[:-1] |= high_mask[1:]
lower, = ax.plot(x[low_mask], y[low_mask], **outer_style)
mid, = ax.plot(x[mid_mask], y[mid_mask], **inner_style)
upper, = ax.plot(x[high_mask], y[high_mask], **outer_style)
# add vertical lines
vline_low = ax.axvline(low, color='k', ls='--')
vline_high = ax.axvline(high, color='k', ls='--')
hspan = ax.axvspan(low, high, color='b', alpha=.25)
return lower, mid, upper, vline_low, vline_high, hspan
Which can obviously be generalized to take 3 line style dictionaries and style information for the vertical lines and the span. You use it like:
inner_style = {'color': 'r', 'lw': 5, 'ls':'--'}
outer_style = {'color': 'r', 'lw': 1, 'ls':'-'}
x = np.linspace(0, 2*np.pi, 1024)
y = np.sin(x)
low = np.pi / 2
high = 3*np.pi / 2
fig, ax = plt.subplots()
lower, mid, upper, vl_low, vl_high, hsp = split_plot(ax, x, y, low, high, inner_style, outer_style)
plt.show()
Upvotes: 2