简体   繁体   中英

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

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).

我试图将其不确定性绘制为填充区域的数据图表。使用 <code>plt.fill()</code> 会产生填充的节点。

What I would like to accomplish is a point-to-point filling, ie, 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()

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

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM