Python 3.7: Fill area between two lines with different x-axes values that zigzag a lot

限于喜欢 提交于 2021-02-11 18:07:11

问题


I have a dataset whose uncertainty I would like to represent as a filled region around the main plot. The errors are large in the x-axes direction, so I have not been able to use plt.fill_between(x, y1, y2), which requires a common set of x-axes.

I have tried using plt.fill(np.append(x1, x2[::-1])) as suggested elsewhere on this website, but because my data zigzags up and down a lot, the filled regions end up looking like nodes (see attached figure).

What I would like to accomplish is a point-to-point filling, i.e., filling the region between the i-th value of the lower bound and the i-th value of the upper bound for every value of i, such that main line with the actual data is always within the filled region..

The code I'm currently using is attached below. Thanks in advance for your advice/help!

import numpy as np
import matplotlib.pyplot as plt


# Generate data
data = [  # 1st set
        np.asarray([[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147],
                    [0.95655418,0.968751302,0.983557511,1,0.990592677,0.97449496,0.95440505,0.924954671,0.886996122,0.82251848,0.778125913,0.73916151,0.700254675,0.668987694,0.63055911,0.590810638,0.555342043,0.507765573,0.4616611,0.429145607,0.413109798,0.390302561,0.363457831,0.342211112,0.318108912,0.294919636,0.2604157,0.234729394,0.215631188,0.19881722,0.183199438,0.16849855,0.155955983,0.139366571,0.130774073,0.122769502,0.113845958,0.108554715,0.100988871,0.096328988,0.089256135,0.084745413,0.079921355,0.074552516,0.069711584,0.065973993,0.063518416,0.060676971,0.057921448,0.054652475,0.052496131,0.049222527,0.046675798,0.044500797,0.043952159,0.041155119,0.043656139,0.040926506,0.039692837,0.037439469,0.036360189,0.035155463,0.033663854,0.032398257,0.03094279,0.029410186,0.028667612,0.02746653,0.026438134,0.025641696,0.024370006,0.023830637,0.023306691,0.021891054,0.020939248,0.019839459,0.019218755,0.019261568,0.019029851,0.018123198,0.01710584,0.016715688,0.01618066,0.015785562,0.014618372,0.013970195,0.013450019,0.0130316,0.012526295,0.012519175,0.0111811,0.010592157,0.010524284,0.010147982,0.010100317,0.009651263,0.009243377,0.009168683,0.008427179,0.008649776,0.00849209,0.008433903,0.008057094,0.007496825,0.007536894,0.007522125,0.007019614,0.007308734,0.006747738,0.006585782,0.006723507,0.006146523,0.005883389,0.006014114,0.005708983,0.005689707,0.00532408,0.005527866,0.00545286,0.004954855,0.004833038,0.004554934,0.004251427,0.004186365,0.004252841,0.003897866,0.003731514,0.003545388,0.003436594,0.003431516,0.003253962,0.002831155,0.002969271,0.001684758,0.001340519,0.001385708,0.001303324,0.001303421,0.001044814,0.001077059,0.001093969]]),
          # 2nd set
        np.asarray([[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95],
                    [0.914033852,0.950504849,0.80004654,0.695783944,0.662746701,0.695576344,0.90154606,1,0.81140764,0.678474576,0.634939708,0.607590316,0.518639178,0.207727727,0.216432158,0.224586428,0.279720169,0.245618979,0.222696026,0.199679098,0.179142946,0.158946171,0.14188248,0.127260706,0.112782138,0.100888414,0.089853204,0.08216043,0.073372773,0.067958601,0.061487526,0.055911548,0.050893264,0.046562233,0.042915263,0.039707178,0.036378441,0.033371983,0.030817107,0.028757013,0.026475762,0.024725777,0.022679087,0.020535423,0.019044371,0.017906946,0.016977675,0.016137162,0.015026638,0.013821426,0.012863647,0.011716813,0.011141965,0.010609055,0.00977254,0.009348052,0.008344767,0.007617324,0.007495344,0.006615654,0.006292315,0.006144333,0.005258415,0.004866276,0.004712482,0.004014683,0.004069901,0.00361893,0.003229981,0.003008768,0.003020642,0.00285177,0.00227489,0.002182672,0.001804809,0.001610111,0.001768367,0.001669851,0.001623464,0.001456057,0.001114707,0.0011109,0.001091451,0.001165129,0.000900596,0.000952285,0.000960306,0.000922442,0.000836143]]),
          # 3rd set        
        np.asarray([[5,6,7,8,9,10,11,12,13,14,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],
                    [1,0.927662075,0.96202778,0.924335135,0.828600389,0.613168998,0.434280748,0.33575471,0.226712113,0.179613025,0.094097102,0.132828886,0.183557076,0.139710035,0.101280635,0.07329473,0.056400289,0.043787685,0.033451036,0.026281189,0.019311693,0.015875145,0.014837602,0.012488443,0.011285327,0.009343611,0.008602607,0.007826083,0.006956754,0.005454963,0.005808192]]),
          # 4th set
        np.asarray([[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365],
                    [0.885909672,1,0.99162113,0.872488779,0.87398788,0.805963959,0.74319068,0.726634486,0.740202316,0.730969223,0.670578511,0.624200235,0.613225969,0.575205857,0.609029515,0.597698204,0.57980882,0.576631664,0.581497131,0.593804795,0.606824276,0.640333687,0.634379114,0.656129569,0.663956949,0.634547791,0.595586735,0.581772148,0.569338853,0.555159526,0.545101106,0.525147065,0.502896746,0.497743379,0.493600401,0.49762563,0.477230369,0.482063433,0.477360682,0.467838442,0.467380429,0.47560526,0.468880058,0.487816836,0.480472169,0.467176897,0.460125843,0.448287451,0.437142557,0.42658121,0.413663556,0.408012163,0.402944298,0.395960648,0.392914203,0.385336533,0.382498637,0.380576939,0.375302121,0.372433499,0.372657596,0.371524779,0.367985585,0.366572768,0.368253803,0.371552111,0.378665281,0.384730649,0.391524758,0.393310424,0.400383444,0.412549566,0.419823185,0.429974348,0.443500171,0.467968688,0.476722667,0.480154755,0.485114033,0.49532665,0.491100296,0.487384531,0.48849776,0.495426176,0.495257257,0.481092465,0.436619122,0.408269466,0.374306761,0.373166502,0.382555796,0.378342072,0.346950265,0.317572698,0.252999696,0.153670297,0.136906858,0.128124111,0.118055812,0.11413037,0.110161997,0.10628067,0.098298601,0.093111985,0.088350851,0.08576681,0.079879986,0.074838647,0.072270659,0.068716759,0.066169679,0.065067294,0.064145231,0.061806894,0.060669599,0.059005956,0.057686128,0.05512712,0.053881379,0.052239032,0.051214915,0.050582681,0.049530671,0.048884795,0.051156767,0.049774256,0.0514431,0.05146419,0.051118524,0.050911102,0.049803011,0.049447797,0.048438409,0.048405349,0.046723778,0.046154424,0.04552512,0.044032249,0.043395595,0.043308933,0.042585152,0.041754058,0.040325688,0.039175667,0.039162313,0.037457688,0.037956389,0.037296581,0.036296388,0.035926523,0.035588571,0.034830947,0.035225701,0.034703098,0.033922258,0.033755366,0.033411962,0.032572077,0.032549764,0.032282915,0.032172298,0.031884569,0.031313459,0.031114445,0.031373301,0.031243683,0.031569485,0.030555099,0.031135214,0.031321489,0.030749573,0.029966772,0.03061446,0.030135384,0.030585367,0.029686435,0.02988313,0.029481707,0.02910797,0.029261633,0.029571263,0.029690859,0.028788667,0.028728067,0.028809428,0.029128161,0.028235243,0.02782359,0.027672193,0.027629457,0.027277172,0.027107321,0.026965431,0.026783799,0.026939647,0.026590097,0.026175666,0.026194135,0.025958189,0.025875979,0.026209379,0.02533026,0.025988519,0.025428073,0.018142192,0.018212207,0.017783734,0.017665953,0.017192459,0.016945588,0.016437243,0.016641711,0.016239232,0.016401381,0.015912438,0.016196707,0.016107538,0.015733245,0.015514499,0.015532215,0.015836562,0.015428837,0.0157516,0.014978627,0.014932577,0.014423966,0.014887073,0.014867981,0.014573822,0.014581828,0.014697673,0.014533383,0.014405806,0.014522672,0.014052074,0.014218667,0.014169407,0.014463344,0.014302986,0.013865811,0.013956405,0.014048572,0.013790196,0.014130022,0.014036684,0.014114657,0.014071971,0.013703234,0.013826223,0.013563827,0.013678588,0.013383205,0.013217588,0.013010951,0.012847964,0.013262616,0.013069786,0.013113281,0.013071785,0.012477441,0.012546062,0.012646679,0.012860151,0.012243156,0.012315449,0.012518825,0.012396436,0.012397889,0.012489189,0.012442466,0.012540196,0.012643484,0.01227506,0.012253067,0.011976709,0.012023984,0.011997722,0.012033947,0.012080226,0.012191508,0.011918882,0.011854949,0.011518262,0.011825999,0.011507567,0.011218112,0.011136758,0.010964953,0.011244613,0.011005658,0.010895433,0.011235724,0.010974862,0.010672335,0.010636289,0.010645618,0.010843378]])]

# Generate color set
color_set = ["blue",
             "red",
             "green",
             "orange"]

# Create figure to plot data in
plt.figure(figsize=(4, 3)).add_axes([0.1,
                                     0.1,
                                     0.8,
                                     0.8])
# Iterate through data and plot it
for i in range(0, len(data)):
    d = data[i]

    # Create lists
    x = d[0] * 6
    y = d[1]
    x_err = 0.1 * x
    y_err = 0.01 * y

    # Set lower and upper bounds for error region    
    x_lo = x - x_err
    x_hi = x + x_err
    y_lo = y - y_err
    y_hi = y + y_err

    # Set color
    color = color_set[i]

    # Plot lines
    plt.plot(x, y,
             linestyle="-",
             linewidth=1.0,
             marker="o",
             markersize=2,
             color=color)

    """
    PYPLOT FILL
    This method involves filling an area defined by the high and low errors in
    the x and y axes directions. However, regions of overlap appear darker in
    colour, which is not ideal

    # Generate shaded region of uncertainty
    plt.fill(np.append(x_lo, x_hi[::-1]),
             np.append(y_lo, y_hi[::-1]),
             color=color,
             linewidth=0.0,
             alpha=0.5)
    """

    """
    SHAPELY POLYGON
    This method was introduced by @William Miller on StackExchange, and makes use 
    of the "shapely" Python module. A polygon describing the region of error is 
    first defined for each point, and the polygons are then merged together and 
    the region is filled
    """

    for k in range(1, len(d)):
        # Check to see what the polygon is like
        """
        Not all the regions in this method overlap

        area = geometry.Polygon([(x_lo[k - 1], y_lo[k - 1]),
                                 (x_lo[k], y_lo[k]),
                                 (x_hi[k], y_lo[k]),
                                 (x_hi[k], y_hi[k]),
                                 (x_hi[k - 1], y_hi[k - 1]),
                                 (x_lo[k - 1], y_hi[k - 1])])
        """
        """
        # Polygon describing error around each point
        area1 = geometry.Polygon([(x_lo[k - 1], y[k - 1]),
                                  (x[k - 1], y_lo[k - 1]),
                                  (x_hi[k - 1], y[k - 1]),
                                  (x[k - 1], y_hi[k - 1])])
        area2 = geometry.Polygon([(x_lo[k], y[k]),
                                  (x[k], y_lo[k]),
                                  (x_hi[k], y[k]),
                                  (x[k], y_hi[k])])
        # Polygon bridging the two points
        area3 = geometry.Polygon([(x_lo[k - 1], y[k - 1]),
                                  (x_lo[k], y[k]),
                                  (x_hi[k], y[k]),
                                  (x_hi[k - 1], y[k - 1])])
        area4 = geometry.Polygon([(x[k - 1], y_lo[k - 1]),
                                  (x[k], y_lo[k]),
                                  (x[k], y_hi[k]),
                                  (x[k - 1], y_hi[k - 1])])
        area = cascaded_union([area1, area2, area3, area4])
        area_x, area_y = area.exterior.xy
        plt.gca().add_patch(patches.Polygon(np.stack([area_x, area_y], 1),
                                            facecolor=color,
                                            alpha=0.2))
        """

    err_shaded = []
    for k in range(1, len(d)):
        # Polygon defining error region for each point
        area1 = geometry.Polygon([(x_lo[k - 1], y[k - 1]),
                                  (x[k - 1], y_lo[k - 1]),
                                  (x_hi[k - 1], y[k - 1]),
                                  (x[k - 1], y_hi[k - 1])])
        area2 = geometry.Polygon([(x_lo[k], y[k]),
                                  (x[k], y_lo[k]),
                                  (x_hi[k], y[k]),
                                  (x[k], y_hi[k])])
        # Polygon bridging the two points
        # Bridge along x errors
        area3 = geometry.Polygon([(x_lo[k - 1], y[k - 1]),
                                  (x_lo[k], y[k]),
                                  (x_hi[k], y[k]),
                                  (x_hi[k - 1], y[k - 1])])
        # Bridge along y errors
        area4 = geometry.Polygon([(x[k - 1], y_lo[k - 1]),
                                  (x[k], y_lo[k]),
                                  (x[k], y_hi[k]),
                                  (x[k - 1], y_hi[k - 1])])
        # Merge the areas together
        area = cascaded_union([area1, area2, area3, area4])
        # Append the shaded error region for this point to the list
        err_shaded.append(area)
    err_shaded = cascaded_union(err_shaded)
    area_x, area_y = err_shaded.exterior.xy
    plt.gca().add_patch(patches.Polygon(np.stack([area_x, area_y], 1),
                                        facecolor=color,
                                        alpha=0.2))

plt.savefig(r"test_plot_err_shaded.png",
            figsize=(4, 3),
            dpi=300)
plt.close()

回答1:


Is this more like what you're looking for?

You can create this by breaking the polygons that get filled with plt.fill() into smaller pieces of the x_lo, x_hi, y_lo, and y_hi arrays and filling each segment separately like this

from matplotlib.colors import to_rgb
color = to_rgb(color_set[i])
for k in range(1, len(x), 1):
    xe = [x_lo[k], x_lo[k-1], x_hi[k-1], x_hi[k]]
    ye = [y_lo[k], y_lo[k-1], y_hi[k-1], y_hi[k]]
    plt.fill(xe, ye, fc=(color[0], color[1], color[2], 0.3))

This isn't really the best way to go about this but it might work well enough for your purposes. A slightly more robust approach is to create a cascaded union using shapely.ops.cascaded_union,

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import to_rgb
from matplotlib import patches
from shapely.ops import cascaded_union
from shapely import geometry

# Unchanged code omitted

for i in range(0, len(data)):
    # Unchanged code omitted
    # Set color
    color = to_rgb(color_set[i])
    color = (color[0], color[1], color[2], 0.3)

    # Plot lines
    plt.plot(x, y, linestyle="-", linewidth=1.0, marker="o", markersize=2, color=color)
    # Plot region of error
    polygons = list()
    for k in range(1, len(x), 1):
        polygons.append(geometry.Polygon([(x_lo[k], y_lo[k]), (x_lo[k-1], y_lo[k-1]), 
                                          (x_hi[k-1], y_hi[k-1]), (x_hi[k], y_hi[k])]))

    boundary = cascaded_union(polygons)
    x, y = boundary.exterior.xy
    ax.add_patch(patches.Polygon(np.stack([x, y], 1), fc=color))

plt.show()

which will give you something that looks like this



来源:https://stackoverflow.com/questions/59200776/python-3-7-fill-area-between-two-lines-with-different-x-axes-values-that-zigzag

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!