Align matplotlib markup marker left and right

I use the scatter function matplotlibto create the appearance of pens in vertical lines to outline certain parts of the graph. However, to make them look right, I need to link the scatter marker marker on the left (for the left line / limiter) and / or to the right (for the right line / limiter).

Here is an example:

#create the figure
fig = plt.figure(facecolor = '#f3f3f3', figsize = (11.5, 6))
ax = plt. ax = plt.subplot2grid((1, 1), (0,0))

#make some random data
index = pandas.DatetimeIndex(start = '01/01/2000', freq  = 'b', periods = 100)
rand_levels = pandas.DataFrame( numpy.random.randn(100, 4)/252., index = index, columns = ['a', 'b', 'c', 'd'])
rand_levels = 100*numpy.exp(rand_levels.cumsum(axis = 0))
ax.stackplot(rand_levels.index, rand_levels.transpose())

#create the place holder for the vertical lines
d1, d2 = index[25], index[50]

#draw the lines
ymin, ymax = ax.get_ylim()
ax.vlines([index[25], index[50]], ymin = ymin, ymax = ymax, color = '#353535', lw = 2)

#draw the markers
ax.scatter(d1, ymax, clip_on = False, color = '#353535', marker = '>', s = 200, zorder = 3)
ax.scatter(d2, ymax, clip_on = False, color = '#353535', marker = '<', s = 200, zorder = 3)

#reset the limits
ax.set_ylim(ymin, ymax)
ax.set_xlim(rand_levels.index[0], rand_levels.index[-1])
plt.show()

The code above gives me almost the graph I'm looking for, for example:

focus_timeline

, , ( " > " ) " " (.. ), . , , ( "<" ) " " (.. ). :

desired_fig

, ?

.. DataFrame pandas.Datetime , .

+4
4

. , (mark_align_*). verts ( 2- Nx2, (0, 0)). , ,

from matplotlib import markers
from matplotlib.path import Path

def align_marker(marker, halign='center', valign='middle',):
    """
    create markers with specified alignment.

    Parameters
    ----------

    marker : a valid marker specification.
      See mpl.markers

    halign : string, float {'left', 'center', 'right'}
      Specifies the horizontal alignment of the marker. *float* values
      specify the alignment in units of the markersize/2 (0 is 'center',
      -1 is 'right', 1 is 'left').

    valign : string, float {'top', 'middle', 'bottom'}
      Specifies the vertical alignment of the marker. *float* values
      specify the alignment in units of the markersize/2 (0 is 'middle',
      -1 is 'top', 1 is 'bottom').

    Returns
    -------

    marker_array : numpy.ndarray
      A Nx2 array that specifies the marker path relative to the
      plot target point at (0, 0).

    Notes
    -----
    The mark_array can be passed directly to ax.plot and ax.scatter, e.g.::

        ax.plot(1, 1, marker=align_marker('>', 'left'))

    """

    if isinstance(halign, (str, unicode)):
        halign = {'right': -1.,
                  'middle': 0.,
                  'center': 0.,
                  'left': 1.,
                  }[halign]

    if isinstance(valign, (str, unicode)):
        valign = {'top': -1.,
                  'middle': 0.,
                  'center': 0.,
                  'bottom': 1.,
                  }[valign]

    # Define the base marker
    bm = markers.MarkerStyle(marker)

    # Get the marker path and apply the marker transform to get the
    # actual marker vertices (they should all be in a unit-square
    # centered at (0, 0))
    m_arr = bm.get_path().transformed(bm.get_transform()).vertices

    # Shift the marker vertices for the specified alignment.
    m_arr[:, 0] += halign / 2
    m_arr[:, 1] += valign / 2

    return Path(m_arr, bm.get_path().codes)

, ,

ax.plot(d1, 1, marker=align_marker('>', halign='left'), ms=20,
        clip_on=False, color='k', transform=ax.get_xaxis_transform())
ax.plot(d2, 1, marker=align_marker('<', halign='right'), ms=20,
        clip_on=False, color='k', transform=ax.get_xaxis_transform())

ax.scatter,

ax.scatter(d1, 1, 200, marker=align_marker('>', halign='left'),
           clip_on=False, color='k', transform=ax.get_xaxis_transform())
ax.scatter(d2, 1, 200, marker=align_marker('<', halign='right'),
           clip_on=False, color='k', transform=ax.get_xaxis_transform())

transform=ax.get_xaxis_transform() , (1 - ), .

, , (ax.plot vs. ax.scatter) ( ). !

!

+5

mpl.transforms, transform - ax.scatter ax.plot. ,

from matplotlib import transforms as tf

tf.offset_copy , . ? , ax.scatter ax.plot -. . .

  • s= ax.scatter ^ 2 (.. , ).

  • markersize ax.plot (.. , ).

ax.scatter

, ax.scatter, ,

ms_scatter = 200  # define markersize
mark_align_left_scatter = tf.offset_copy(ax.get_xaxis_transform(), fig,
                                         ms_scatter ** 0.5 / 2,
                                         units='points')
mark_align_right_scatter = tf.offset_copy(ax.get_xaxis_transform(), fig,
                                          -ms_scatter ** 0.5 / 2,
                                          units='points')

ax.get_xaxis_transform, , x, ( 0 1) y. , ymax, 1. , , ! , transform ax.scatter,

ax.scatter(d1, 1, s=ms_scatter, marker='>', transform=mark_align_left_scatter,
           clip_on=False, color='k')
ax.scatter(d2, 1, s=ms_scatter, marker='<', transform=mark_align_right_scatter,
           clip_on=False, color='k')

ax.plot

, , , ax.plot. ,

ms = 20

mark_align_left = tf.offset_copy(ax.get_xaxis_transform(), fig,
                                 ms / 2, units='points')
mark_align_right = tf.offset_copy(ax.get_xaxis_transform(), fig,
                                  -ms / 2, units='points')

ax.plot(d1, 1, marker='>', ms=ms, transform=mark_align_left,
        clip_on=False, color='k')
ax.plot(d2, 1, marker='<', ms=ms, transform=mark_align_right,
        clip_on=False, color='k')

, mark_align_*, , .

ax.scatter ax.plot, :

Final figure

+2

Not the most elegant solution, but if I understand your question correctly, subtract and add it from / to d1and d2accordingly:

ax.scatter(d1-1, ymax, clip_on = False, color = '#353535', marker = '>', s = 200, zorder = 3)
ax.scatter(d2+1, ymax, clip_on = False, color = '#353535', marker = '<', s = 200, zorder = 3)
0
source

I found a simple solution to this problem. Matplotlib have built-in markers with different settings: code_bars_and_markers code example: marker_reference.py

Just change the marker >to 9and the marker <to 8:

#draw the markers
ax.scatter(d1, ymax, clip_on=False, color='#353535', marker=9, s=200, zorder=3)
ax.scatter(d2, ymax, clip_on=False, color='#353535', marker=8, s=200, zorder=3)
0
source

All Articles