Search code examples
pythonmatplotlibazure-functionsazure-storage

Read Azure Storage blob into matplotlib


I'm working with matplotlib.pyplot and Azure Storage blobs (azure.storage.blob) in a Azure Functions environment (should not access the file system).

My goal is to get a blob:

service = blob.BlobServiceClient(account_url="https://mysa.blob.core.windows.net", credential=SA_PRIMARY_KEY)
blob_client = service.get_blob_client(container="mycontainer", blob="myimg.JPG")
blob_data = blob_client.download_blob()

And open it with pyplot using imread like:

img = plt.imread(blob_data_to_read_opened_stream, format="JPG")

So I think I'm missing a piece. After obtaining the blob_data object it's needed to copy it's content into a stream passing it to pyplot

with open("./BlockDestination.jpg", "wb") as blob_stream:
    blob_data = blob.download_blob()
    blob_data.readinto(blob_stream)
    img = plt.imread(blob_stream, format="JPG")

This would fail cause imread needs a

file-like object opened in read-binary mode

How can I achieve my goal without opening two different streams?


Solution

  • You can generate a SAS token and use it to read images from your storage account directly instead of download images and read them. It will ease the server pressure and only one read stream here. Just try the code below:

    from azure.storage.blob import ResourceTypes, AccountSasPermissions, generate_account_sas,BlobServiceClient
    from datetime import datetime, timedelta
    import matplotlib.pyplot as plt
    import matplotlib.patches as patches
    import matplotlib.cbook as cbook
    
    connStr = '<storage account connection string>'
    containerName ='<container name>'
    blobName = "<image name>"
    
    blob_service_client = BlobServiceClient.from_connection_string(connStr)
    
    sas_token = generate_account_sas(
        blob_service_client.account_name,
        account_key=blob_service_client.credential.account_key,
        resource_types=ResourceTypes(object=True),
        permission=AccountSasPermissions(read=True),
        expiry=datetime.utcnow() + timedelta(hours=1)
    )
    
    destImageUrl = blob_service_client.primary_endpoint + containerName + "/" + blobName + "?" + sas_token
    
    image  = plt.imread(destImageUrl , format="JPG")
    
    fig, ax = plt.subplots()
    im = ax.imshow(image)
    patch = patches.Circle((260, 200), radius=200, transform=ax.transData)
    im.set_clip_path(patch)
    
    ax.axis('off')
    plt.show()
    

    My .jpg file content:

    enter image description here

    Result:

    enter image description here