18

I am stuck with a (hopefully) simple problem. My aim is to plot a dashed line interrupted with data (not only text).

Example of how I would imagine a possible result

As I only found out to create a dashed line via linestyle = 'dashed', any help is appreciated to put the data between the dashes.

Something similar, regarding the labeling, is already existing with Matplotlib - as I saw in the contour line demo.

Matplotlib Contour Demo

Update:

The question link mentioned by Richard in comments was very helpful, but not the 100% like I mentioned via comment. Currently, I do it this way:

line_string2 = '-10 ' + u"\u00b0" +"C"
l, = ax1.plot(T_m10_X_Values,T_m10_Y_Values)
pos = [(T_m10_X_Values[-2]+T_m10_X_Values[-1])/2., (T_m10_Y_Values[-2]+T_m10_Y_Values[-1])/2.]
# transform data points to screen space
xscreen = ax1.transData.transform(zip(T_m10_Y_Values[-2::],T_m10_Y_Values[-2::]))
rot = np.rad2deg(np.arctan2(*np.abs(np.gradient(xscreen)[0][0][::-1])))
ltex = plt.text(pos[0], pos[1], line_string2, size=9, rotation=rot, color='b',ha="center", va="bottom",bbox = dict(ec='1',fc='1', alpha=0.5))

Here you can see a snapshot of the result. The minus 20°C is without BBox.

enter image description here

Community
  • 1
  • 1
Matthias
  • 183
  • 5
  • 1
    Hi - I've edited in the pictures to the question. Could you edit in a [MInimal, Complete and Verifiable Example](http://stackoverflow.com/help/mcve) i.e. the code you are currently using to plot your lines and the data you would like to put in between dashes? Then we may be able to help - I don't think there's a simple "one-size-fits-all" solution like "use the style=dashes_with_labels" or anything. – J Richard Snape Jul 30 '15 at 11:44
  • 1
    Actually - you may want to check out this question and answer http://stackoverflow.com/questions/19876882/print-string-over-plotted-line-mimic-contour-plot-labels. It may be enough. If this is not - and you can't adapt them to get the repeating you want - add a reference to these in your question (to show you're aware) and specify that the repeating label is important to you. – J Richard Snape Jul 30 '15 at 11:49
  • Hi everyone, that mentioned link from Richard was the bulls eye, at least it seemed so. The result is exactly what i need. But I have a grid behind visualized via imshow and not white background. There one can see, that the dashed line with text is the result of a bbox, which overwrites the line. Working with zorder did not do the trick either. But with this solution so far I can live. If there is no other way. – Matthias Aug 02 '15 at 20:04
  • I think you want the 20 to appear in front of all the other things in your graph. You need to investigate the `zorder` property. Put simply, the higher the `zorder`, the further "on top" the thing is plotted. Your call to `plt.text` is [documented here](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.figtext) and you can see that you can set `zorder`. So try changing that call to `plt.text(pos[0], pos[1], line_string2, size=9, rotation=rot, color='b',ha="center", va="bottom", zorder=100)` and see if that's what you want. – J Richard Snape Aug 03 '15 at 13:20
  • You should note - you can set the `zorder` on a number of matplotlib calls, controlling which elements plot in front of which others. – J Richard Snape Aug 03 '15 at 13:21

1 Answers1

1

Quick and dirty answer using annotate:

import matplotlib.pyplot as plt
import numpy as np

x = list(reversed([1.81,1.715,1.78,1.613,1.629,1.714,1.62,1.738,1.495,1.669,1.57,1.877,1.385]))
y = [0.924,0.915,0.914,0.91,0.909,0.905,0.905,0.893,0.886,0.881,0.873,0.873,0.844]

def plot_with_text(x, y, text, text_count=None):
    text_count = (2 * (len(x) / len(text))) if text_count is None else text_count
    fig, ax = plt.subplots(1,1)
    l, = ax.plot(x,y)
    text_size = len(text) * 10
    idx_step = len(x) / text_count
    for idx_num in range(text_count):
        idx = int(idx_num * idx_step)
        text_pos = [x[idx], y[idx]]
        xscreen = ax.transData.transform(zip(x[max(0, idx-1):min(len(x), idx+2)], y[max(0, idx-1):min(len(y), idx+2)]))
        a = np.abs(np.gradient(xscreen)[0][0])
        rot = np.rad2deg(np.arctan2(*a)) - 90
        ax.annotate(text, xy=text_pos, color="r", bbox=dict(ec="1", fc="1", alpha=0.9), rotation=rot, ha="center", va="center")

plot_with_text(x, y, "test")

Yields:

plot

You can play with the offsets for more pleasing results.

mtd
  • 2,224
  • 19
  • 21