|
| 1 | +""" |
| 2 | +========================= |
| 3 | +Combining Transformations |
| 4 | +========================= |
| 5 | +
|
| 6 | +This example showcases how to combine transformations, including Affine |
| 7 | +and blended transformations. |
| 8 | +
|
| 9 | +Some time data is plotted on axes that have significant disparity |
| 10 | +between the x- and y-scales. To place circular markers on some events |
| 11 | +that scale in the y-direction proprtionally to the data, while |
| 12 | +remaining perfectly circular in display space, we blend a reflected |
| 13 | +version of the y-data transform into the x axis. |
| 14 | +
|
| 15 | +As a secondary item, this example shows how to work with datetimes |
| 16 | +along one axis when constructing patches such as rectangles. |
| 17 | +""" |
| 18 | + |
| 19 | +from datetime import datetime |
| 20 | +from matplotlib import ( |
| 21 | + dates as mdate, |
| 22 | + patches as mpatch, |
| 23 | + pyplot as plt, |
| 24 | + transforms as mtrans |
| 25 | +) |
| 26 | +import numpy as np |
| 27 | + |
| 28 | +data = { |
| 29 | + "A": [datetime(2024, 4, 10, 3, 10, 22), |
| 30 | + datetime(2024, 4, 10, 3, 21, 13), |
| 31 | + datetime(2024, 4, 10, 3, 25, 41)], |
| 32 | + "B": [datetime(2024, 4, 10, 3, 15, 55), |
| 33 | + datetime(2024, 4, 10, 3, 40, 8)], |
| 34 | + "C": [datetime(2024, 4, 10, 3, 12, 18), |
| 35 | + datetime(2024, 4, 10, 3, 23, 32), |
| 36 | + datetime(2024, 4, 10, 3, 32, 12)], |
| 37 | +} |
| 38 | + |
| 39 | +fig, ax = plt.subplots(constrained_layout=True) |
| 40 | +ax.invert_yaxis() |
| 41 | + |
| 42 | +# Some of the transforms only need to be set up once |
| 43 | +vertical_scale_transform = mtrans.AffineDeltaTransform(ax.transData) |
| 44 | +reflection = mtrans.Affine2D.from_values(0, 1, 1, 0, 0, 0) |
| 45 | +uniform_scale_transform = mtrans.blended_transform_factory( |
| 46 | + reflection + vertical_scale_transform + reflection, vertical_scale_transform) |
| 47 | + |
| 48 | +# Draw some rectangle spanning each dataset |
| 49 | +for i, dates in enumerate(data.values()): |
| 50 | + start = mdate.date2num(dates[0]) |
| 51 | + end = mdate.date2num(dates[-1]) |
| 52 | + width = end - start |
| 53 | + color = ax._get_lines.get_next_color() |
| 54 | + ax.add_patch(mpatch.Rectangle((start, i - 0.4), width, 0.8, color=color)) |
| 55 | + |
| 56 | + # Draw a circle at each event |
| 57 | + for event in dates: |
| 58 | + x = mdate.date2num(event) |
| 59 | + ax.add_patch(mpatch.Circle((0, 0), 0.2, facecolor="w", edgecolor="k", linewidth=2, |
| 60 | + transform=uniform_scale_transform + mtrans.ScaledTranslation(x, i, ax.transData))) |
| 61 | + |
| 62 | +# Set the y-axis to show the data labels |
| 63 | +ax.set_yticks(np.arange(len(data))) |
| 64 | +ax.set_yticklabels(list(data)) |
| 65 | + |
| 66 | +# Set the x-axis to display datetimes |
| 67 | +ax.xaxis.set_major_locator(locator := mdate.AutoDateLocator()) |
| 68 | +ax.xaxis.set_major_formatter(mdate.AutoDateFormatter(locator)) |
| 69 | + |
| 70 | +ax.autoscale_view() |
| 71 | + |
| 72 | +plt.show() |
0 commit comments