1

Is there a way to force the dashed line of a plotted curve to touch both axes (top and bottom)? Specifically, I'm looking to find a way to specify the start position (xstart, ystart) and end position (xend, yend) of the dash so I can force it to touch the axes. Here's an example to show the problem:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 5, 10)
y = np.power(x,3.0)+80

plt.plot(x,y+5, '--')
plt.axis(xmin=0,xmax=5,ymin=100,ymax=150)

plot

grover
  • 927
  • 1
  • 10
  • 21
  • Try `ylim` `xlim` to arbitrarily set your intercepts relative to your data. – roadrunner66 Mar 17 '16 at 06:05
  • Doesn't this just make the plot window smaller? I would prefer to not have to sacrifice my plot range to get this to work. – grover Mar 17 '16 at 06:14
  • I may have misunderstood then. Could you give a full executable yet minimal example showing the problem? – roadrunner66 Mar 17 '16 at 06:16
  • I edited to include the code. I want the dashed line to touch the bottom y-axis at y=100 and the top y-axis at y=150. – grover Mar 17 '16 at 06:18
  • You mean top and bottom x-axes at y=100 and 150? That's what the picture shows and what I see when I run your example. Only difference is that the dash is 'off' at first, so it appears disconnected, but by no more than one dash-length. – roadrunner66 Mar 17 '16 at 06:41
  • 1
    See this link : http://stackoverflow.com/questions/14710221/python-matplotlib-dash-dot-dot-how-to for finer dash control and how in that example the lines are touching. So I was wrong, the dash style should always start with the dash 'on' and it should fit up to the line as you requested. – roadrunner66 Mar 17 '16 at 06:49
  • This seems to be just a way to modify the frequency and separation of the dashes. I'm looking for a way to hard code the start and end dash locations with (x,y) values. – grover Mar 17 '16 at 07:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/106549/discussion-between-roadrunner66-and-grover). – roadrunner66 Mar 17 '16 at 07:13

1 Answers1

1

Following the comment by roadrunner66 I assembled an example that works for me

l, = plt.plot(x,y+5)
l.set_dashes([5,2])
plt.axis(xmin=0,xmax=5,ymin=100,ymax=150)

If you want to automate this, I guess one needs to know the length of your line as well in order to calculate the right dashes.

To obtain the length of the line in display coordinates could do something like

xl,yl=l.get_xydata().T
xmin, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()

# Filter out the points outside the range & replace them with a point on the axis
m = ((xl >= xmin) & (xl <= xmax)) & ((yl >= ymin) & (yl <= ymax))
x = np.concatenate([[xmin], xl[m], [xmax]])
y = np.concatenate([[ymin], yl[m], [ymax]])
xt, yt = ax.transData.transform(np.vstack([xl,yl]).T).T
length = np.sum( np.sqrt((xt[1:] - xt[:-1])**2 + (yt[1:] - yt[:-1])**2))

Now given this length we can calculate a reasonable tick length & spacing in between

length = np.sum( np.sqrt((x[1:] - x[:-1])**2 + (y[1:] - y[:-1])**2))
tickl = 5.
minspace = 2.
i = int(length / (tickl + minspace))
space = length / i - tickl # since length = i * (space + tickl)
print space

This gives me a value of 2.39086935951 so 2 wasn't a too bad guess.

user1834164
  • 377
  • 3
  • 13
  • 1
    You can also do this as `plt.plot(x, y, linestyle=(0, [5, 2])`. The 0 is the 'offset' (how many pixels into the cycle the 'start' is and works properly on the 2.x and master branches (but not in any released version of mpl :/) – tacaswell Mar 18 '16 at 02:43
  • @tacaswell this now works in released versions! You should definitely submit an answer to this thread, as it solves the problem more simply. It should be the accepted solution. – Luke Davis Sep 05 '17 at 20:41