ম্যাটপ্লোটিলেবতে একটি রঙিন মানচিত্রের মিডপয়েন্টটি নির্ধারণ করা


88

আমি একটি রঙিন মানচিত্রের মধ্যম পয়েন্টটি সেট করতে চাই, অর্থাত আমার ডেটা -5 থেকে 10 এ চলে যায়, আমি শূন্যকে মাঝখানে হতে চাই। আমি মনে করি এটি করার উপায়টি সাধারণভাবে সাবক্লাসিং করা এবং নিয়মটি ব্যবহার করা হয় তবে আমি এর কোন উদাহরণ পাই না এবং এটি আমার কাছে পরিষ্কার নয় যে আমাকে ঠিক কীভাবে প্রয়োগ করতে হবে।


একে বলা হয় "ডাইভারজিং" বা "বাইপোলার" কালার ম্যাপ, যেখানে মানচিত্রের কেন্দ্রবিন্দু গুরুত্বপূর্ণ এবং ডেটা এই পয়েন্টের উপরে এবং নীচে যায়। Sandia.gov/~kmorel/documents/CororMaps
এন্ডোলিথ

4
এই থ্রেডের সমস্ত উত্তর বরং জটিল বলে মনে হচ্ছে। সমাধানের সহজ সমাধানটি এই দুর্দান্ত উত্তরে দেখানো হয়েছে , যা ইতিমধ্যে এটি ম্যাটপ্ল্লিটিব ডকুমেন্টেশন, বিভাগ কাস্টম নরমালাইজেশন: দুটি লিনিয়ার রেঞ্জকেও তৈরি করেছে ।
ImportanceOfBeingEnnest

উত্তর:


15

লক্ষ্য করুন matplotlib সংস্করণ 3.1 মধ্যে DivergingNorm বর্গ যোগ করা হয়েছিল। আমি মনে করি এটি আপনার ব্যবহারের ক্ষেত্রে কভার করে। এটি এর মতো ব্যবহার করা যেতে পারে:

from matplotlib import colors
colors.DivergingNorm(vmin=-4000., vcenter=0., vmax=10000)

ম্যাটপ্ল্লোলিব ৩.২-এ ক্লাসটির নামকরণ করা হয়েছে টু স্লোপসনর্মে


এটি আকর্ষণীয় দেখায় তবে মনে হয় এটি ষড়যন্ত্রের আগে ডেটা রূপান্তর করতে ব্যবহার করতে হবে। কালার বারটির কিংবদন্তি রূপান্তরিত ডেটার সাথে সম্পর্কিত হবে, মূলটি নয়।
bli

4
@ ব্লি যে ঘটনা না। normআপনার ইমেজ জন্য নিয়মমাফিককরণ আছে। normscolormaps সঙ্গে একসাথে যান।
পল এইচ

4
Annoyingly এটি কোন ডক সঙ্গে 3.2 এ অনুমোদিত নয় হিসেবে কিভাবে এটি প্রতিস্থাপন করতে: matplotlib.org/3.2.0/api/_as_gen/...
daknowles

4
হ্যাঁ ডক্সটি অস্পষ্ট। আমি মনে করি এটি পুনরায় নাম দেওয়া হয়েছে TwoSlopeNorm: matplotlib.org/3.2.0/api/_as_gen/...
macKaiver

91

আমি জানি যে এই গেমটি দেরীতে হয়েছে তবে আমি কেবল এই প্রক্রিয়াটি পেরিয়েছিলাম এবং এমন একটি সমাধান নিয়ে এসেছি যা সম্ভবত সাবক্লাসিংয়ের চেয়ে কম দৃust়তর স্বাভাবিক, তবে আরও সহজ। আমি ভেবেছিলাম উত্তরসূরীদের জন্য এটি এখানে ভাগ করে নেওয়া ভাল।

কাজ

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import AxesGrid

def shiftedColorMap(cmap, start=0, midpoint=0.5, stop=1.0, name='shiftedcmap'):
    '''
    Function to offset the "center" of a colormap. Useful for
    data with a negative min and positive max and you want the
    middle of the colormap's dynamic range to be at zero.

    Input
    -----
      cmap : The matplotlib colormap to be altered
      start : Offset from lowest point in the colormap's range.
          Defaults to 0.0 (no lower offset). Should be between
          0.0 and `midpoint`.
      midpoint : The new center of the colormap. Defaults to 
          0.5 (no shift). Should be between 0.0 and 1.0. In
          general, this should be  1 - vmax / (vmax + abs(vmin))
          For example if your data range from -15.0 to +5.0 and
          you want the center of the colormap at 0.0, `midpoint`
          should be set to  1 - 5/(5 + 15)) or 0.75
      stop : Offset from highest point in the colormap's range.
          Defaults to 1.0 (no upper offset). Should be between
          `midpoint` and 1.0.
    '''
    cdict = {
        'red': [],
        'green': [],
        'blue': [],
        'alpha': []
    }

    # regular index to compute the colors
    reg_index = np.linspace(start, stop, 257)

    # shifted index to match the data
    shift_index = np.hstack([
        np.linspace(0.0, midpoint, 128, endpoint=False), 
        np.linspace(midpoint, 1.0, 129, endpoint=True)
    ])

    for ri, si in zip(reg_index, shift_index):
        r, g, b, a = cmap(ri)

        cdict['red'].append((si, r, r))
        cdict['green'].append((si, g, g))
        cdict['blue'].append((si, b, b))
        cdict['alpha'].append((si, a, a))

    newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict)
    plt.register_cmap(cmap=newcmap)

    return newcmap

একটি উদাহরণ

biased_data = np.random.random_integers(low=-15, high=5, size=(37,37))

orig_cmap = matplotlib.cm.coolwarm
shifted_cmap = shiftedColorMap(orig_cmap, midpoint=0.75, name='shifted')
shrunk_cmap = shiftedColorMap(orig_cmap, start=0.15, midpoint=0.75, stop=0.85, name='shrunk')

fig = plt.figure(figsize=(6,6))
grid = AxesGrid(fig, 111, nrows_ncols=(2, 2), axes_pad=0.5,
                label_mode="1", share_all=True,
                cbar_location="right", cbar_mode="each",
                cbar_size="7%", cbar_pad="2%")

# normal cmap
im0 = grid[0].imshow(biased_data, interpolation="none", cmap=orig_cmap)
grid.cbar_axes[0].colorbar(im0)
grid[0].set_title('Default behavior (hard to see bias)', fontsize=8)

im1 = grid[1].imshow(biased_data, interpolation="none", cmap=orig_cmap, vmax=15, vmin=-15)
grid.cbar_axes[1].colorbar(im1)
grid[1].set_title('Centered zero manually,\nbut lost upper end of dynamic range', fontsize=8)

im2 = grid[2].imshow(biased_data, interpolation="none", cmap=shifted_cmap)
grid.cbar_axes[2].colorbar(im2)
grid[2].set_title('Recentered cmap with function', fontsize=8)

im3 = grid[3].imshow(biased_data, interpolation="none", cmap=shrunk_cmap)
grid.cbar_axes[3].colorbar(im3)
grid[3].set_title('Recentered cmap with function\nand shrunk range', fontsize=8)

for ax in grid:
    ax.set_yticks([])
    ax.set_xticks([])

উদাহরণের ফলাফল:

এখানে চিত্র বর্ণনা লিখুন


আপনার দুর্দান্ত অবদানের জন্য অনেক ধন্যবাদ! তবে কোডটি একই রঙের মানচিত্রটি ক্রপ এবং স্থান পরিবর্তন করতে উভয়ই সক্ষম ছিল না এবং আপনার নির্দেশাবলী কিছুটা অসম্পূর্ণ এবং বিভ্রান্তিকর ছিল। আমি এখন এটি স্থির করেছি এবং আপনার পোস্ট সম্পাদনা করার জন্য স্বাধীনতা নিয়েছি। এছাড়াও, আমি এটিকে আমার ব্যক্তিগত লাইব্রেরিতে অন্তর্ভুক্ত করেছি এবং আপনাকে লেখক হিসাবে যুক্ত করেছি। আশা করি কিছু মনে করবেন না.
থিমের

@ ছায়ামেরা নীচের ডানদিকে কোণার বর্ণমালা উভয়ই ক্রপড এবং পুনরায় স্থান পেয়েছে। আপনি উপযুক্ত হিসাবে দেখতে এটি নির্দ্বিধায়।
পল এইচ

হ্যাঁ, এটি আছে, দুঃখের বিষয় এটি কেবল একটি কাকতালীয় হিসাবে প্রায় সঠিক দেখায়। যদি startএবং stop0 এবং 1 যথাক্রমে, আপনি কি পরে না reg_index = np.linspace(start, stop, 257), আপনি আর অনুমান করতে পারেন যে মান 129, মূল cmap এর মধ্যবিন্দু তাই সমগ্র rescaling কোন মানে যখনই আপনি ক্রপ করে তোলে। এছাড়াও, আপনার নির্দেশ অনুসারে start0 থেকে 0.5 এবং stop0.5 থেকে 1 পর্যন্ত হওয়া উচিত , উভয়ই 0 থেকে 1 নয়।
থিমেরার

@ ছায়ামেরা আমি আপনার সংস্করণটি চেষ্টা করেছিলাম এবং এ সম্পর্কে দুটি চিন্তাভাবনা করেছি। 1) আমার কাছে মনে হয় আপনি তৈরি সূচকগুলি 257 দৈর্ঘ্যের, এবং ম্যাটপ্ল্লোলিবতে এটি 256 এ ডিফল্ট হয়েছে আমি ধরে নিই? 2) ধরুন আমার ডেটা -1 থেকে 1000 এর পরিসীমা, এটি ইতিবাচক দ্বারা প্রভাবিত এবং সুতরাং আরও স্তর / স্তরগুলি ইতিবাচক শাখায় যাওয়া উচিত। তবে আপনার ফাংশনটি নেতিবাচক এবং ধনাত্মক উভয়কেই 128 স্তর দেয়, সুতরাং আমি মনে করি অসমভাবে স্তরগুলি বিভক্ত করা আরও "ন্যায্য" হবে।
জেসন

এটি একটি দুর্দান্ত সমাধান, তবে midpointডেটা 0 বা 1 এর সমান হলে এটি ব্যর্থ হয় that সমস্যার সরল সমাধানের জন্য নীচে আমার উত্তরটি দেখুন।
ডেভ দ্যসাইন্টিস্ট

22

এখানে নর্মালাইজাইনের একটি সাবক্লাসিং সমাধান রয়েছে। এটি ব্যবহার করতে

norm = MidPointNorm(midpoint=3)
imshow(X, norm=norm)

এখানে ক্লাস:

import numpy as np
from numpy import ma
from matplotlib import cbook
from matplotlib.colors import Normalize

class MidPointNorm(Normalize):    
    def __init__(self, midpoint=0, vmin=None, vmax=None, clip=False):
        Normalize.__init__(self,vmin, vmax, clip)
        self.midpoint = midpoint

    def __call__(self, value, clip=None):
        if clip is None:
            clip = self.clip

        result, is_scalar = self.process_value(value)

        self.autoscale_None(result)
        vmin, vmax, midpoint = self.vmin, self.vmax, self.midpoint

        if not (vmin < midpoint < vmax):
            raise ValueError("midpoint must be between maxvalue and minvalue.")       
        elif vmin == vmax:
            result.fill(0) # Or should it be all masked? Or 0.5?
        elif vmin > vmax:
            raise ValueError("maxvalue must be bigger than minvalue")
        else:
            vmin = float(vmin)
            vmax = float(vmax)
            if clip:
                mask = ma.getmask(result)
                result = ma.array(np.clip(result.filled(vmax), vmin, vmax),
                                  mask=mask)

            # ma division is very slow; we can take a shortcut
            resdat = result.data

            #First scale to -1 to 1 range, than to from 0 to 1.
            resdat -= midpoint            
            resdat[resdat>0] /= abs(vmax - midpoint)            
            resdat[resdat<0] /= abs(vmin - midpoint)

            resdat /= 2.
            resdat += 0.5
            result = ma.array(resdat, mask=result.mask, copy=False)                

        if is_scalar:
            result = result[0]            
        return result

    def inverse(self, value):
        if not self.scaled():
            raise ValueError("Not invertible until scaled")
        vmin, vmax, midpoint = self.vmin, self.vmax, self.midpoint

        if cbook.iterable(value):
            val = ma.asarray(value)
            val = 2 * (val-0.5)  
            val[val>0]  *= abs(vmax - midpoint)
            val[val<0] *= abs(vmin - midpoint)
            val += midpoint
            return val
        else:
            val = 2 * (value - 0.5)
            if val < 0: 
                return  val*abs(vmin-midpoint) + midpoint
            else:
                return  val*abs(vmax-midpoint) + midpoint

আরও সাব-ক্লাস তৈরি না করে লগ বা সিম-লগ স্কেলিং ছাড়াও এই শ্রেণিটি ব্যবহার করা সম্ভব? আমার বর্তমান ব্যবহারের কেসটি ইতিমধ্যে "আদর্শ = সিমলগনর্ম (লিনথ্রেশ = 1)"
আনানফায়

নিখুঁত, আমি ঠিক এটিই খুঁজছিলাম। পার্থক্যটি প্রদর্শনের জন্য আপনার কোনও ছবি যুক্ত করা উচিত? এখানে মিডপয়েন্টটি বারে কেন্দ্রীভূত হয়, অন্য মিডপয়েন্টের নরমালাইজারগুলির বিপরীতে যেখানে মিডপয়েন্টটি চূড়ান্ততার দিকে টানা যায়।
চমত্কার

18

সাবক্লাসিংয়ের পরিবর্তে (আপনি চিত্রের ডেটা নিয়ে কাজ করছেন বলে ধরে নেওয়া) এর পক্ষে যুক্তি vminএবং vmaxতর্কগুলি ব্যবহার করা সবচেয়ে সহজ ।imshowmatplotlib.colors.Normalize

যেমন

import numpy as np
import matplotlib.pyplot as plt

data = np.random.random((10,10))
# Make the data range from about -5 to 10
data = 10 / 0.75 * (data - 0.25)

plt.imshow(data, vmin=-10, vmax=10)
plt.colorbar()

plt.show()

এখানে চিত্র বর্ণনা লিখুন


4
গাউসিয়ান বক্ররেখার সাথে উদাহরণটি আপডেট করা কি সম্ভব যাতে আমরা আরও ভাল করে রঙের গ্রেডিং দেখতে পারি?
ডেটা চু

4
আমি এই সমাধানটি পছন্দ করি না, কারণ এটি উপলব্ধ রঙগুলির সম্পূর্ণ গতিশীল পরিসর ব্যবহার করে না। এছাড়াও আমি সিমলগ ধরণের নরমালাইজেশন তৈরির জন্য সাধারণকরণের একটি উদাহরণ চাই।
টিলেস্টেন

4
@ টিটলস্টেন - আমি বিভ্রান্ত হয়ে পড়েছি ... তবে আপনি যদি মাঝখানে 0 চান, তবে আপনি রঙবারের পুরো গতিশীল পরিসরটি ব্যবহার করতে পারবেন না? আপনি কি তখন কোনও লিনিয়ার স্কেল চান? 0 এর উপরে মানের জন্য একটি স্কেল, নীচের মানের জন্য একটি? হ্যাঁ, আপনাকে সাবক্লাস করতে হবে Normalize। আমি কিছুটা উদাহরণ দিয়ে যুক্ত করব (ধরে নিলাম অন্য কেউ আমাকে এতে মারবেন না ...)।
জো কিংটন

@ জো: আপনি ঠিক বলেছেন, এটি লিনিয়ার নয় (আরও সঠিকভাবে, দুটি রৈখিক অংশ)। ভিএমএন / ভিএমএক্স ব্যবহার করে -5-এর চেয়ে কম মানগুলির জন্য কালারঞ্জ ব্যবহার করা হয় না (যা কিছু অ্যাপ্লিকেশনগুলিতে বোঝা যায় তবে আমার নয়))।
টিলেস্টেন

4
জেডে জেনেরিক ডেটার জন্য:vmax=abs(Z).max(), vmin=-abs(Z).max()
এন্ডোলিথ

13

এখানে আমি Normalizeএকটি সর্বনিম্ন উদাহরণ অনুসরণ করে একটি সাবক্লাস তৈরি করি ।

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt


class MidpointNormalize(mpl.colors.Normalize):
    def __init__(self, vmin, vmax, midpoint=0, clip=False):
        self.midpoint = midpoint
        mpl.colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        normalized_min = max(0, 1 / 2 * (1 - abs((self.midpoint - self.vmin) / (self.midpoint - self.vmax))))
        normalized_max = min(1, 1 / 2 * (1 + abs((self.vmax - self.midpoint) / (self.midpoint - self.vmin))))
        normalized_mid = 0.5
        x, y = [self.vmin, self.midpoint, self.vmax], [normalized_min, normalized_mid, normalized_max]
        return np.ma.masked_array(np.interp(value, x, y))


vals = np.array([[-5., 0], [5, 10]]) 
vmin = vals.min()
vmax = vals.max()

norm = MidpointNormalize(vmin=vmin, vmax=vmax, midpoint=0)
cmap = 'RdBu_r' 

plt.imshow(vals, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()

ফলাফল: pic-1

শুধুমাত্র ইতিবাচক ডেটা সহ একই উদাহরণ vals = np.array([[1., 3], [6, 10]])

ছবি -২

বৈশিষ্ট্য:

  • মিডপয়েন্টটি মাঝের রঙটি পায়।
  • উপরের এবং নিম্ন রেঞ্জগুলি একই লিনিয়ার রূপান্তর দ্বারা পুনরুদ্ধার করা হয়।
  • ছবিতে প্রদর্শিত রঙটি কেবল রঙ বারে প্রদর্শিত হবে।
  • এর vminচেয়ে বড় হলেও সূক্ষ্ম কাজ করার জন্য মনে হয় midpoint(যদিও সমস্ত প্রান্তের কেসগুলি পরীক্ষা করে নি)।

এই পৃষ্ঠাটি থেকে এই নামটি একই নাম সহ কোনও শ্রেণীর দ্বারা অনুপ্রাণিত হয়


4
সরলতার কারণে সেরা উত্তর অন্য উত্তরগুলি কেবল তখনই সেরা যদি আপনি ইতিমধ্যে একজন বিশেষজ্ঞ-বিশেষজ্ঞ হওয়ার চেষ্টা করছেন ম্যাটপ্লটলিব বিশেষজ্ঞ। বেশিরভাগ ম্যাটপ্ল্লোলিব উত্তর সন্ধানকারীরা তাদের কুকুর এবং / অথবা পরিবারের কাছে বাড়িতে যাওয়ার জন্য কেবল কিছু করার চেষ্টা করছেন এবং তাদের জন্য এই উত্তরটি সর্বোত্তম।
sapo_cosmico

এই সমাধানটি সত্যই সেরা বলে মনে হচ্ছে, তবে কাজ করে না! আমি কেবল পরীক্ষার স্ক্রিপ্টটি চালিয়েছি এবং ফলাফলটি সম্পূর্ণ আলাদা (কেবল নীল স্কোয়ার এবং কোনও লাল নয়)। @ আইসেমটেল, আপনি কি চেক করতে পারেন? (ইনডেন্টেশন সমস্যাটি ছাড়াও def __call__)
ফিলিপ

ঠিক আছে, আমি সমস্যা (গুলি) পাওয়া গেছে: হিসাব নম্বর normalized_minএবং normalized_maxপূর্ণসংখ্যার যেমন নেয়া হয়। এগুলি 0.0 হিসাবে রাখুন। এছাড়াও, আপনার চিত্রের সঠিক আউটপুট পেতে, আমাকে ব্যবহার করতে হয়েছিল vals = sp.array([[-5.0, 0.0], [5.0, 10.0]]) । উত্তরের জন্য ধন্যবাদ, যাইহোক!
ফিলিপ

হাই @ ফিলিপ আমি আমার মেশিনে আপনার সমস্যাটি পুনরুত্পাদন করতে পারি না (পাইথন ৩.7, ম্যাটপ্ল্লোব ২.২.৩, এবং আমার মনে হয় নতুন সংস্করণগুলিতে একই হওয়া উচিত)। আপনার কি সংস্করণ আছে? যাইহোক, আমি ভাসা জাতীয় ধরণের অ্যারে তৈরি করে একটি ছোট সম্পাদনা করেছি এবং ইনডেন্টেশন সমস্যাটি স্থির করেছি। এটি
দেখানোর

হুম .. আমি পাইথন 3 দিয়ে চেষ্টা করেছি এবং এটিও কাজ করে। তবে আমি পাইথন 2.7 ব্যবহার করছি। ঠিক করার জন্য এবং উত্তরের জন্য আপনাকে ধন্যবাদ। এটি ব্যবহার করা খুব সহজ! :)
ফিলিপ

5

আপনি এখনও উত্তর খুঁজছেন কিনা তা নিশ্চিত নন। আমার জন্য, সাবক্লাস করার চেষ্টা Normalizeকরা ব্যর্থ হয়েছিল। সুতরাং আমি আপনাকে লক্ষ্য করে যাচ্ছি বলে মনে করি সেই প্রভাব পেতে আমি নিজেই একটি নতুন ডেটা সেট, টিক্স এবং টিক-লেবেল তৈরি করার দিকে মনোনিবেশ করেছি।

আমি scaleম্যাটপ্লটলিবের মডিউলটি পেয়েছি যার একটি ক্লাস 'সিসলগ' বিধি দ্বারা লাইন প্লটগুলিকে রূপান্তর করতে ব্যবহৃত হয়েছে, তাই আমি ডেটা রূপান্তর করতে এটি ব্যবহার করি। তারপরে আমি ডেটাটি স্কেল করি যাতে এটি 0 থেকে 1 ( Normalizeসাধারণত কী হয়) থেকে যায় তবে আমি ইতিবাচক সংখ্যাগুলি নেতিবাচক সংখ্যার চেয়ে আলাদাভাবে স্কেল করি। এটি কারণ আপনার ভিএমএক্স এবং ভিমন একরকম নাও হতে পারে, তাই .5 -> 1 টি .5 -> 0 এর চেয়ে বড় ধনাত্মক সীমাটি কভার করতে পারে, theণাত্মক পরিসরটি করে। টিক এবং লেবেলের মানগুলি গণনা করার জন্য একটি রুটিন তৈরি করা আমার পক্ষে সহজ ছিল।

নীচে কোড এবং একটি উদাহরণ চিত্র।

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mpl as mpl
import matplotlib.scale as scale

NDATA = 50
VMAX=10
VMIN=-5
LINTHRESH=1e-4

def makeTickLables(vmin,vmax,linthresh):
    """
    make two lists, one for the tick positions, and one for the labels
    at those positions. The number and placement of positive labels is 
    different from the negative labels.
    """
    nvpos = int(np.log10(vmax))-int(np.log10(linthresh))
    nvneg = int(np.log10(np.abs(vmin)))-int(np.log10(linthresh))+1
    ticks = []
    labels = []
    lavmin = (np.log10(np.abs(vmin)))
    lvmax = (np.log10(np.abs(vmax)))
    llinthres = int(np.log10(linthresh))
    # f(x) = mx+b
    # f(llinthres) = .5
    # f(lavmin) = 0
    m = .5/float(llinthres-lavmin)
    b = (.5-llinthres*m-lavmin*m)/2
    for itick in range(nvneg):
        labels.append(-1*float(pow(10,itick+llinthres)))
        ticks.append((b+(itick+llinthres)*m))
    # add vmin tick
    labels.append(vmin)
    ticks.append(b+(lavmin)*m)

    # f(x) = mx+b
    # f(llinthres) = .5
    # f(lvmax) = 1
    m = .5/float(lvmax-llinthres)
    b = m*(lvmax-2*llinthres) 
    for itick in range(1,nvpos):
        labels.append(float(pow(10,itick+llinthres)))
        ticks.append((b+(itick+llinthres)*m))
    # add vmax tick
    labels.append(vmax)
    ticks.append(b+(lvmax)*m)

    return ticks,labels


data = (VMAX-VMIN)*np.random.random((NDATA,NDATA))+VMIN

# define a scaler object that can transform to 'symlog'
scaler = scale.SymmetricalLogScale.SymmetricalLogTransform(10,LINTHRESH)
datas = scaler.transform(data)

# scale datas so that 0 is at .5
# so two seperate scales, one for positive and one for negative
data2 = np.where(np.greater(data,0),
                 .75+.25*datas/np.log10(VMAX),
                 .25+.25*(datas)/np.log10(np.abs(VMIN))
                 )

ticks,labels=makeTickLables(VMIN,VMAX,LINTHRESH)

cmap = mpl.cm.jet
fig = plt.figure()
ax = fig.add_subplot(111)
im = ax.imshow(data2,cmap=cmap,vmin=0,vmax=1)
cbar = plt.colorbar(im,ticks=ticks)
cbar.ax.set_yticklabels(labels)

fig.savefig('twoscales.png')

ভিএমএক্স = 10, ভিমন = -5 এবং লিনথ্রেশ = 1 ই -4

VMAXএটি ভাল আচরণ করে তা নিশ্চিত করার জন্য স্ক্রিপ্টের শীর্ষে "ধ্রুবকগুলি" (উদাঃ ) সামঞ্জস্য করতে নির্দ্বিধায় অনুভব করুন ।


আপনার পরামর্শের জন্য ধন্যবাদ, নীচের মত দেখা গেছে, সাবক্লাসিংয়ে আমার সাফল্য ছিল। তবে আপনার কোডটি টিক্লেবেলগুলি সঠিক করার জন্য এখনও খুব কার্যকর।
tillsten

4

আমি পল এইচ-এর কাছ থেকে চমৎকার উত্তরটি ব্যবহার করছিলাম, তবে একটি সমস্যার মধ্যে পড়েছিলাম কারণ আমার কিছু ডেটা নেতিবাচক থেকে ধনাত্মক পর্যন্ত, অন্য সেটগুলি 0 থেকে ধনাত্মক বা নেতিবাচক থেকে 0 পর্যন্ত ছিল; উভয় ক্ষেত্রেই আমি 0 টি সাদা হিসাবে রঙিন হতে চেয়েছি (আমি যে রঙিনম্যাপটি ব্যবহার করছি তার মাঝখানে)। বিদ্যমান প্রয়োগের সাথে যদি আপনার midpointমান 1 বা 0 এর সমান হয় তবে মূল ম্যাপিংগুলি ওভাররাইট করা হবে না। আপনি এটি নীচের ছবিতে দেখতে পাচ্ছেন: সম্পাদনার আগে গ্রাফ ২ য় কলামটি সঠিক দেখাচ্ছে তবে ২ য় কলামের গা blue় নীল অঞ্চল এবং অবশিষ্ট কলামগুলির মধ্যে গা red় লাল অঞ্চল সমস্তই সাদা বলে গণ্য হয়েছে (তাদের ডেটা মানগুলি আসলে 0)। আমার ফিক্সটি ব্যবহার করে আমাকে দেয়: সম্পাদনার পরে গ্রাফ আমার ফাংশনটি মূলত পল এইচ-এর মতোই, forলুপের শুরুতে আমার সম্পাদনাগুলির সাথে :

def shiftedColorMap(cmap, min_val, max_val, name):
    '''Function to offset the "center" of a colormap. Useful for data with a negative min and positive max and you want the middle of the colormap's dynamic range to be at zero. Adapted from /programming/7404116/defining-the-midpoint-of-a-colormap-in-matplotlib

    Input
    -----
      cmap : The matplotlib colormap to be altered.
      start : Offset from lowest point in the colormap's range.
          Defaults to 0.0 (no lower ofset). Should be between
          0.0 and `midpoint`.
      midpoint : The new center of the colormap. Defaults to
          0.5 (no shift). Should be between 0.0 and 1.0. In
          general, this should be  1 - vmax/(vmax + abs(vmin))
          For example if your data range from -15.0 to +5.0 and
          you want the center of the colormap at 0.0, `midpoint`
          should be set to  1 - 5/(5 + 15)) or 0.75
      stop : Offset from highets point in the colormap's range.
          Defaults to 1.0 (no upper ofset). Should be between
          `midpoint` and 1.0.'''
    epsilon = 0.001
    start, stop = 0.0, 1.0
    min_val, max_val = min(0.0, min_val), max(0.0, max_val) # Edit #2
    midpoint = 1.0 - max_val/(max_val + abs(min_val))
    cdict = {'red': [], 'green': [], 'blue': [], 'alpha': []}
    # regular index to compute the colors
    reg_index = np.linspace(start, stop, 257)
    # shifted index to match the data
    shift_index = np.hstack([np.linspace(0.0, midpoint, 128, endpoint=False), np.linspace(midpoint, 1.0, 129, endpoint=True)])
    for ri, si in zip(reg_index, shift_index):
        if abs(si - midpoint) < epsilon:
            r, g, b, a = cmap(0.5) # 0.5 = original midpoint.
        else:
            r, g, b, a = cmap(ri)
        cdict['red'].append((si, r, r))
        cdict['green'].append((si, g, g))
        cdict['blue'].append((si, b, b))
        cdict['alpha'].append((si, a, a))
    newcmap = matplotlib.colors.LinearSegmentedColormap(name, cdict)
    plt.register_cmap(cmap=newcmap)
    return newcmap

সম্পাদনা: আমি আবারও একই ধরণের সমস্যায় পড়েছিলাম যখন আমার কিছু ডেটা একটি ছোট ধনাত্মক মান থেকে বৃহত্তর ধনাত্মক মান পর্যন্ত ছিল, যেখানে খুব কম মানগুলি সাদা রঙের পরিবর্তে লাল রঙের হয়ে উঠছিল। Edit #2উপরের কোডটিতে লাইন যুক্ত করে আমি এটি ঠিক করেছি ।


এটি দেখতে দুর্দান্ত দেখাচ্ছে তবে মনে হচ্ছে পল এইচ (এবং মন্তব্যগুলি) এর উত্তর থেকে যুক্তিগুলি পরিবর্তিত হয়েছে ... আপনি কি নিজের উত্তরে একটি উদাহরণ কল যুক্ত করতে পারেন?
ফিলিপ

1

আপনি যদি ভিএমএন, ভিএমএক্স এবং শূন্যের মধ্যে অনুপাতটি কাজ করতে আপত্তি করেন না, তবে এটি নীল থেকে সাদা থেকে লাল রঙের একটি খুব ভাল লিনিয়ার মানচিত্র, যা অনুপাত অনুসারে সাদা সেট করে z:

def colormap(z):
    """custom colourmap for map plots"""

    cdict1 = {'red': ((0.0, 0.0, 0.0),
                      (z,   1.0, 1.0),
                      (1.0, 1.0, 1.0)),
              'green': ((0.0, 0.0, 0.0),
                        (z,   1.0, 1.0),
                        (1.0, 0.0, 0.0)),
              'blue': ((0.0, 1.0, 1.0),
                       (z,   1.0, 1.0),
                       (1.0, 0.0, 0.0))
              }

    return LinearSegmentedColormap('BlueRed1', cdict1)

সিডিক্ট ফর্ম্যাটটি মোটামুটি সহজ: সারিগুলি গ্রেডিয়েন্টের মধ্যে বিন্দু যা তৈরি হয়: প্রথম এন্ট্রিটি হ'ল এক্স-মান (0 থেকে 1 থেকে গ্রেডিয়েন্টের সাথে অনুপাত), দ্বিতীয়টি পূর্ববর্তী বিভাগের শেষ মান এবং এবং তৃতীয়টি হ'ল পরবর্তী বিভাগের জন্য শুরুর মান - যদি আপনি মসৃণ গ্রেডিয়েন্ট চান তবে পরের দুটিটি সর্বদা একই থাকে। আরও বিশদ জন্য ডক্স দেখুন


4
LinearSegmentedColormap.from_list()টিপলসগুলির মধ্যে নির্দিষ্ট করে (val,color)এবং colorএই পদ্ধতির যুক্তির তালিকায় তাদের তালিকা হিসাবে পাস করার বিকল্প রয়েছে val0=0<val1<...<valN==1
মরিজিও

0

আমার একই রকম সমস্যা ছিল, তবে আমি সর্বোচ্চ মানটি পুরো লাল হওয়া এবং নীলের নীচের মানগুলি কেটে দিতে চেয়েছিলাম, এটি রঙিনবারের নীচের অংশের মতো কাটা কাটার মতো দেখতে মূলত দেখা দেয়। এটি আমার পক্ষে কাজ করেছে (transparencyচ্ছিক স্বচ্ছতা সহ):

def shift_zero_bwr_colormap(z: float, transparent: bool = True):
    """shifted bwr colormap"""
    if (z < 0) or (z > 1):
        raise ValueError('z must be between 0 and 1')

    cdict1 = {'red': ((0.0, max(-2*z+1, 0), max(-2*z+1, 0)),
                      (z,   1.0, 1.0),
                      (1.0, 1.0, 1.0)),

              'green': ((0.0, max(-2*z+1, 0), max(-2*z+1, 0)),
                        (z,   1.0, 1.0),
                        (1.0, max(2*z-1,0),  max(2*z-1,0))),

              'blue': ((0.0, 1.0, 1.0),
                       (z,   1.0, 1.0),
                       (1.0, max(2*z-1,0), max(2*z-1,0))),
              }
    if transparent:
        cdict1['alpha'] = ((0.0, 1-max(-2*z+1, 0), 1-max(-2*z+1, 0)),
                           (z,   0.0, 0.0),
                           (1.0, 1-max(2*z-1,0),  1-max(2*z-1,0)))

    return LinearSegmentedColormap('shifted_rwb', cdict1)

cmap =  shift_zero_bwr_colormap(.3)

x = np.arange(0, np.pi, 0.1)
y = np.arange(0, 2*np.pi, 0.1)
X, Y = np.meshgrid(x, y)
Z = np.cos(X) * np.sin(Y) * 5 + 5
plt.plot([0, 10*np.pi], [0, 20*np.pi], color='c', lw=20, zorder=-3)
plt.imshow(Z, interpolation='nearest', origin='lower', cmap=cmap)
plt.colorbar()
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.