Измененный цвет

#python #matplotlib #plot #graph

#python #matplotlib #сюжет #График

Вопрос:

Я пытаюсь добиться этого идеального графического форматирования графика: введите описание изображения здесь

Я успешно сгенерировал график, также каким-то образом ( plt.pcolor ) перезаписал цвета графика по умолчанию (что, возможно, излишне, но я не могу найти другой вариант), но я борюсь с этим:

  1. Следующий цветовой слой имеет смещение к основной сетке

введите описание изображения здесь

  1. Я также понятия не имею, как удалить все галочки (sticks) сверху, слева, вниз, но сохранить метки
  2. И я хотел бы сместить верхние метки еще ниже
  3. Я также хочу добавить 3 условия для цвета. Синий цвет также может быть постепенным синим в зависимости от первого цвета графика

введите описание изображения здесь

Вот функциональный код для генерации графика (на среднем рисунке):

 import numpy as np
import pandas as pd
from datetime import datetime as dt
from datetime import timedelta
import matplotlib
import matplotlib.pyplot as plt
from calendar import monthrange
import matplotlib.colors as mcolors

def create_graph(all_rows, task_names, farmers):

    harvest = np.array(all_rows)
    fig, ax = plt.subplots()
    im = ax.imshow(harvest)

    # We want to show all ticks...
    ax.set_xticks(np.arange(len(farmers)))
    ax.set_yticks(np.arange(len(task_names)))
    # ... and label them with the respective list entries
    ax.set_xticklabels(farmers, fontsize=4)
    ax.set_yticklabels(task_names, fontsize=8)

    # Rotate the tick labels and set their alignment.
    plt.setp(ax.get_xticklabels(), rotation=0, ha="center", rotation_mode="anchor")
    ax.tick_params(top=True, bottom=False, labeltop=True, labelbottom=False)
    
    #Turn spines off and create white grid.
    for edge, spine in ax.spines.items():
        spine.set_visible(False)

    cmap, norm = mcolors.from_levels_and_colors([0, 1, 4], ['grey', 'green'])

    plt.pcolor(harvest, cmap=cmap, norm=norm, snap=True) 
    ax.set_xticks(np.arange(harvest.shape[1] 1)-.5, minor=True)
    ax.set_yticks(np.arange(harvest.shape[0] 1)-.5, minor=True)
    ax.grid(which="minor", color="w", linestyle='-', linewidth=1)
    
    # ax.tick_params(which="minor", bottom=False, left=False)
    # ax.set_title("Harvest of local farmers (in tons/year)")
    fig.tight_layout()
    plt.show()
    plt.close()


vegetables = ["cucumber", "tomato", "lettuce", "asparagus",
                  "potato", "wheat", "barley"]
farmers = [1, 2, 3, 4, 5, 6, 7]
    
harvest = np.array([[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0],
                    [2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0],
                    [1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0],
                    [0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0],
                    [0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0],
                    [1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1],
                    [0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]])
    
create_graph(harvest, vegetables, farmers)
  

Я пытался посмотреть в matplotlib, но я не стал мудрее, чем раньше.

Комментарии:

1. Вы рисуете это не для большой матрицы, а только для иллюстраций?

Ответ №1:

Некоторые замечания:

  • Чтобы убрать все галочки: ax.tick_params(which='both', length=0) . Обратите внимание, что вы можете вызывать ax.tick_params много раз с разными параметрами. Метки тиков будут автоматически установлены ближе к графику. По умолчанию он работает только с основными тактами, поэтому which='both' он также работает с второстепенными тактами.
  • imshow имеет границы на половинках, которые красиво размещают целочисленные позиции в центре каждой ячейки.
  • pcolor pcolormesh ) предположим, что сетка позиций (по умолчанию для целых чисел), поэтому она плохо согласуется с imshow .
  • Когда второстепенные тики перекрываются с основными, они подавляются. Итак, в этом случае работает простая установка их на значения, кратные 0.5 .
  • vmin и vmax укажите, какое число соответствует самому низкому, а какое — самому высокому цвету цветовой карты.
  • over color может быть установлен для всех значений, превышающих vmax . Это значение может быть отображено на цветовой панели через extend='max' . (По умолчанию для всех значений, превышающих vmax , используется только самый высокий цвет, и аналогично самый низкий цвет для значений ниже vmin ). Обратите внимание, что если вы используете стандартную цветовую карту и хотите использовать set_over , вам нужно сделать копию цветовой карты (потому что set_over изменяется цветовая карта на месте, и вы бы хотели, чтобы другие графики не были затронуты).
  • Цветовая карта по умолчанию называется ‘viridis’. Возможны многие другие.
 import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.ticker import MultipleLocator

def create_graph(all_rows, task_names, farmers):
    harvest = np.array(all_rows)
    fig, ax = plt.subplots()

    # We want to show all ticks...
    ax.set_xticks(np.arange(len(farmers)))
    ax.set_yticks(np.arange(len(task_names)))
    # ... and label them with the respective list entries
    ax.set_xticklabels(farmers, fontsize=4)
    ax.set_yticklabels(task_names, fontsize=8)

    # Rotate the tick labels and set their alignment.
    plt.setp(ax.get_xticklabels(), rotation=0, ha="center", rotation_mode="anchor")
    ax.tick_params(top=True, bottom=False, labeltop=True, labelbottom=False)
    ax.tick_params(which='both', length=0) # hide tick marks
    ax.xaxis.set_minor_locator(MultipleLocator(0.5)) # minor ticks at halves
    ax.yaxis.set_minor_locator(MultipleLocator(0.5)) # minor ticks at halves

    # Turn spines off and create white grid.
    for edge, spine in ax.spines.items():
        spine.set_visible(False)

    cmap = mcolors.LinearSegmentedColormap.from_list("grey-blue", ['grey', 'steelblue'])
    cmap.set_over('green')

    im = ax.imshow(harvest, cmap=cmap, vmin=0, vmax=1)
    ax.grid(which="minor", color="w", linestyle='-', linewidth=1)

    # ax.tick_params(which="minor", bottom=False, left=False)
    # ax.set_title("Harvest of local farmers (in tons/year)")
    plt.colorbar(im, extend='max' , ax=ax)
    fig.tight_layout()
    plt.show()
    #plt.close()


vegetables = ["cucumber", "tomato", "lettuce", "asparagus",
              "potato", "wheat", "barley"]
farmers = [1, 2, 3, 4, 5, 6, 7]

harvest = np.array([[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0],
                    [2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0],
                    [1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0],
                    [0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0],
                    [0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0],
                    [1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1],
                    [0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]])

create_graph(harvest, vegetables, farmers)
  

результирующий график

Приведенный выше код создает цветовую карту, которая плавно переходит от серого при 0 к синему при 1. Если вам нужны специальные цвета для значений 0 и 1 и более стандартная цветовая карта для промежуточных значений, вы могли бы работать с ‘over’, ‘under’ и ‘bad’ цветом. (‘bad’ предназначен для значений, которые бесконечны или не являются числом.) Вы могли бы сделать копию матрицы ‘harvest’ и изменить высокие значения на ‘np.nan’, чтобы придать им особый цвет. К сожалению, нет простого способа показать плохой цвет на цветовой панели, но цвет «под» и «над» можно отобразить с помощью extend='both' и сделать прямоугольным (вместо треугольного) с помощью extendrect=True .

 from copy import copy

cmap = copy(plt.get_cmap('hot'))
cmap.set_under('grey')
cmap.set_over('steelblue')
cmap.set_bad('green')

im = ax.imshow(np.where(harvest <= 1, harvest, np.nan), cmap=cmap, vmin=0.000001, vmax=0.999999)

plt.colorbar(im, extend='both', extendrect=True, ticks=np.arange(0, 1.01, .1), ax=ax)
  

3 специальных цвета

Комментарии:

1. Большое вам спасибо за отличный ответ с множеством вариантов на выбор! Я особенно благодарен за ваше объяснение функций и за ссылку на colormaps. Это действительно помогает мне понять то, что не было понято раньше.

Ответ №2:

Я думаю, plt.pcolor это перебор. Все, что вам нужно сделать, это настроить цветовую карту и применить к imshow . Вот мое решение, основанное на вашем коде.

 import numpy as np
from datetime import datetime as dt
from datetime import timedelta
import matplotlib
import matplotlib.pyplot as plt
from calendar import monthrange
from matplotlib.colors import ListedColormap, to_rgba

def create_graph(all_rows, task_names, farmers):
    harvest = np.array(all_rows)

    # you have to customize the colormap
    rgba = plt.cm.viridis(range(100))
    ind = int(1/harvest.max()*100)
    rgba[0] = to_rgba('gray')
    rgba[ind 1:] = to_rgba('green')
    cmap1 = ListedColormap(rgba)
    
    fig, ax = plt.subplots()
    ax.imshow(harvest, cmap=cmap1)

    # We want to show all ticks...
    ax.set_xticks(np.arange(len(farmers)))
    ax.set_yticks(np.arange(len(task_names)))
    # ... and label them with the respective list entries
    ax.set_xticklabels(farmers, fontsize=4)
    ax.set_yticklabels(task_names, fontsize=8)
    


    # Rotate the tick labels and set their alignment.
    plt.setp(ax.get_xticklabels(), rotation=0, ha="center", rotation_mode="anchor")
    ax.tick_params(top=True, bottom=False, labeltop=True, labelbottom=False)
    
    #Turn spines off and create white grid.
    for edge, spine in ax.spines.items():
        spine.set_visible(False)


    ax.set_xticks(np.arange(harvest.shape[1] 1)-0.5, minor=True)
    ax.set_yticks(np.arange(harvest.shape[0] 1)-0.5, minor=True)
    ax.grid(which="minor", color="w", linestyle='-', linewidth=1)
    
    # ax.tick_params(which="minor", bottom=False, left=False)
    # ax.set_title("Harvest of local farmers (in tons/year)")
    fig.tight_layout()



vegetables = ["cucumber", "tomato", "lettuce", "asparagus",
                  "potato", "wheat", "barley"]
farmers = [1, 2, 3, 4, 5, 6, 7]
    
harvest = np.array([[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0],
                    [2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0],
                    [1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0],
                    [0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0],
                    [0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0],
                    [1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1],
                    [0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3]])
    
create_graph(harvest, vegetables, farmers)
  

введите описание изображения здесь

Комментарии:

1. Большое спасибо за ваше решение, это еще более минималистичный подход, чем предыдущий метод!

Ответ №3:

Это результирующий график, составленный по обоим вашим предложениям!

Это результирующий график, составленный вами обоими!

С чем я борюсь, так это с точной настройкой цветовой карты. Из всех цветовых карт я выбрал эту, но более низкие значения слишком яркие. Есть ли какой-либо способ обрезать цветовую карту, чтобы она не начиналась с этого желтого цвета, но начиналась в диапазоне, который я рисую (красный квадрат)?

Комментарии:

1. Это строка, решающая последнюю задачу! cmap = matplotlib.colors.LinearSegmentedColormap.from_list("", ["#6ECC84","#00492B"]) Еще раз спасибо за вашу огромную помощь!