import os
import numpy as np
import pkg_resources
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
import math
from matplotlib.colors import BoundaryNorm
from meteva.base import IV
import meteva
from matplotlib.collections import LineCollection
import matplotlib.patches as patches
import datetime
import copy

def get_isoline_set(grd):
    values = grd.values
    grid_values = np.squeeze(values)
    vmax = math.ceil(max(grid_values.flatten()))
    vmin = math.ceil(min(grid_values.flatten()))

    dif = (vmax - vmin) / 10.0
    if dif == 0:
        inte = 1
    else:
        inte = math.pow(10, math.floor(math.log10(dif)))
    # 用基本间隔，将最大最小值除于间隔后小数点部分去除，最后把间隔也整数化
    r = dif / inte
    if r < 3 and r >= 1.5:
        inte = inte * 2
    elif r < 4.5 and r >= 3:
        inte = inte * 4
    elif r < 5.5 and r >= 4.5:
        inte = inte * 5
    elif r < 7 and r >= 5.5:
        inte = inte * 6
    elif r >= 7:
        inte = inte * 8
    vmin = inte * ((int)(vmin / inte) - 1)
    vmax = inte * ((int)(vmax / inte) + 1)
    return vmin,vmax,inte

def readshapefile(shapefile, default_encoding='utf-8'):
    """
    """
    import shapefile as shp
    from shapefile import Reader

    if not os.path.exists('%s.shp'%shapefile):
        raise IOError('cannot locate %s.shp'%shapefile)
    if not os.path.exists('%s.shx'%shapefile):
        raise IOError('cannot locate %s.shx'%shapefile)
    if not os.path.exists('%s.dbf'%shapefile):
        raise IOError('cannot locate %s.dbf'%shapefile)
    # open shapefile, read vertices for each object, convert
    # to map projection coordinates (only works for 2D shape types).
    try:
        shp.default_encoding = default_encoding
        shf = Reader(shapefile, encoding=default_encoding)
    except:
        try:
            shp.default_encoding = "gbk"
            shf = Reader(shapefile, encoding="gbk")
        except:
            raise IOError('error reading shapefile %s.shp' % shapefile)

    fields = shf.fields
    coords = []; attributes = []

    shptype = shf.shapes()[0].shapeType
    bbox = shf.bbox.tolist()
    info = (shf.numRecords,shptype,bbox[0:2]+[0.,0.],bbox[2:]+[0.,0.])
    npoly = 0
    for shprec in shf.shapeRecords():
        shp = shprec.shape; rec = shprec.record
        npoly = npoly + 1
        #print(shptype)

        if shptype != shp.shapeType:
            #print(shptype)
            #print(shapefile)
            continue
            #raise ValueError('readshapefile can only handle a single shape type per file')
        if shptype not in [1,3,5,8,13,15]:
            raise ValueError('readshapefile can only handle 2D shape types')
        verts = shp.points
        if shptype in [1,8]: # a Point or MultiPoint shape.
            lons, lats = list(zip(*verts))
            if max(lons) > 721. or min(lons) < -721. or max(lats) > 90.01 or min(lats) < -90.01:
                raise ValueError("经纬度范围超出可能值范围")
            # if latitude is slightly greater than 90, truncate to 90
            lats = [max(min(lat, 90.0), -90.0) for lat in lats]
            if len(verts) > 1: # MultiPoint
                x = lons
                y = lats
                coords.append(list(zip(x,y)))
            else: # single Point
                x = lons[0]
                y = lats[0]
                coords.append((x,y))
            attdict={}
            for r,key in zip(rec,fields[1:]):
                attdict[key[0]]=r
            attributes.append(attdict)
        else: # a Polyline or Polygon shape.
            parts = shp.parts.tolist()
            ringnum = 0
            for indx1,indx2 in zip(parts,parts[1:]+[len(verts)]):
                ringnum = ringnum + 1
                lons, lats = list(zip(*verts[indx1:indx2]))
                if max(lons) > 721. or min(lons) < -721. or max(lats) > 90.01 or min(lats) < -90.01:
                    raise ValueError("经纬度范围超出可能值范围")
                # if latitude is slightly greater than 90, truncate to 90
                lats = [max(min(lat, 90.0), -90.0) for lat in lats]
                #x, y = mp.projtran(lons, lats)  #此处引入投影
                x = lons
                y = lats
                coords.append(list(zip(x,y)))
                attdict={}
                for r,key in zip(rec,fields[1:]):
                    attdict[key[0]]=r
                # add information about ring number to dictionary.
                attdict['RINGNUM'] = ringnum
                attdict['SHAPENUM'] = npoly
                attributes.append(attdict)
    # draw shape boundaries for polylines, polygons  using LineCollection.

    return coords


def set_customized_shpfile_list(shpfile_list = None):
    if shpfile_list is None:
        meteva.base.customized_basemap_list = None
    else:
        meteva.base.customized_basemap_list = []
        for shpfile_filename in shpfile_list:
            if shpfile_filename.find("/") <0 and shpfile_filename.find("\\") <0:
                shpfile = pkg_resources.resource_filename(
                    'meteva', "resources/maps/" + shpfile_filename)

                meteva.base.customized_basemap_list.append(shpfile)
            else:
                meteva.base.customized_basemap_list.append(shpfile_filename)
    #print(meteva.base.customized_basemap_list)

def add_china_map_2basemap(ax,name ="province", facecolor='none',
                           edgecolor='c', lw=2, encoding='utf-8',zorder = 20, **kwargs):
    """
    Add china province boundary to basemap instance.
    :param mp: basemap instance.
    :param ax: matplotlib axes instance.
    :param name: map name.
    :param facecolor: fill color, default is none.
    :param edgecolor: edge color.
    :param lw: line width.
    :param kwargs: keywords passing to Polygon.
    :return: None.
    """
    # map name
    if meteva.base.customized_basemap_list is None:
        # names = {'world':"worldmap",'nation': "bou1_4p", 'province': "Province",
        #          'county': "BOUNT_poly", 'river': "hyd1_4p",
        #          'river_high': "hyd2_4p"}
        #
        # names = {'world':"worldmap",'nation': "NationalBorder", 'province': "Province",
        #          'county': "BOUNT_poly", 'river': "hyd1_4p",
        #          'river_high': "hyd2_4p"}
        #     # get shape file and information
        names = {'world':"worldmap",'nation': "NationalBorder", 'province': "Province",
                 'county': "BOUL_X", 'river': "hyd1_4p",
                 'river_high': "hyd2_4p"}
        shpfile = pkg_resources.resource_filename(
            'meteva', "resources/maps/" + names[name])
        #print(shpfile)
        shp1 = readshapefile(shpfile, default_encoding=encoding)
        lines = LineCollection(shp1,antialiaseds=(1,),zorder=zorder)
        lines.set_color(edgecolor)
        lines.set_linewidth(lw)
        lines.set_label('_nolabel_')
        ax.add_collection(lines)
    else:
        for shpfile in meteva.base.customized_basemap_list:
            #print(shpfile)

            try:
                shp1 = readshapefile(shpfile, default_encoding=encoding)
                lines = LineCollection(shp1,antialiaseds=(1,),zorder=zorder)
                lines.set_color(edgecolor)
                lines.set_linewidth(lw)
                lines.set_label('_nolabel_')
                ax.add_collection(lines)
            except:
                if encoding =="gbk":
                    encoding ="utf-8"
                elif encoding == "utf-8":
                    encoding = "gbk"

                shp1 = readshapefile(shpfile, default_encoding=encoding)
                lines = LineCollection(shp1, antialiaseds=(1,), zorder=zorder)
                lines.set_color(edgecolor)
                lines.set_linewidth(lw)
                lines.set_label('_nolabel_')
                ax.add_collection(lines)


def contourf(grd,save_path = None,title = None,clevs= None,cmap ="rainbow",add_county_line = False,add_worldmap =False,show = False,dpi = 300,
                     sup_fontsize = 10,height = None,width = None,subplot = None,ncol = None,sup_title = None,clip= None,add_minmap= None):
    contourf_2d_grid(grd,save_path = save_path,title = title,clevs= clevs,cmap =cmap,add_county_line = add_county_line,
                     add_worldmap =add_worldmap,show = show,dpi = dpi,
                     sup_fontsize = sup_fontsize,height = height,width = width,subplot = subplot,ncol = ncol,
                     sup_title = sup_title,clip= clip,add_minmap= add_minmap)

def contourf_2d_grid(grd,save_path = None,title = None,clevs= None,cmap ="rainbow",add_county_line = False,add_worldmap =False,show = False,dpi = 300,
                     sup_fontsize = 10,height = None,width = None,subplot = None,ncol = None,sup_title = None,clip= None,add_minmap= None):

    vmin = 10e30
    vmax = -10e30
    if isinstance(grd,list):
        grd_list = grd
        for i in range(len(grd_list)):
            vmax1 = np.max(grd_list[i].values)
            vmin1 = np.max(grd_list[i].values)
            if vmax1 > vmax:vmax = vmax1
            if vmin1 > vmin:vmin = vmin1
    else:
        vmin = np.min(grd.values)
        vmax = np.max(grd.values)
        split = ["member","level", "time", "dtime"]
        if subplot is not None:
            subplot = [subplot]
            for s in subplot:
                split.remove(s)
        grd_list = meteva.base.split_grd(grd, used_coords=split)


    for i in range(len(grd_list)):
        grd1 = grd_list[i]
        if sup_title is None:
            level_str = str(int(grd1["level"].values[0]))
            data_name = grd1["member"].values[0]
            time_str = meteva.base.tool.time_tools.all_type_time_to_str(grd1["time"].values[0])
            dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[6:8] + "日" + time_str[8:10] + "时"
            dtime_str = str(int(grd1["dtime"].values[0]))
            if subplot == ["level"]:
                sup_title1 = data_name + "_" + dati_str + dtime_str + "H时效"
            elif subplot == ["time"]:
                sup_title1 = data_name + "_Level" + level_str + "_" + dtime_str + "H时效"
            elif subplot == ["dtime"]:
                sup_title1 = data_name + "_Level" + level_str + "_" + dati_str
            elif subplot == ["member"]:
                sup_title1 = " Level" + level_str + "_" + dati_str + dtime_str + "H时效"
            else:
                sup_title1 =None
        else:
            if isinstance(sup_title,list):
                sup_title1 = sup_title[i]
            else:
                sup_title1 = sup_title


        if subplot is None:
            grd_list1 = [grd1]
        else:
            grd_list1 = meteva.base.split_grd(grd1, used_coords=subplot)

        len1 = len(grd_list1)
        if title is not None:
            if isinstance(title,list):
                title1 = title[i * len1:i*len1+len1]
            else:
                title1 = title
        else:
            if subplot is not None:
                grd_list1 = meteva.base.split_grd(grd1, used_coords=subplot)
            else:
                grd_list1 = [grd1]
            ng = len(grd_list1)
            title1 = []
            for kk in range(len(grd_list1)):
                grd2 = grd_list1[kk]
                level_str = str(int(grd2["level"].values[0]))
                data_name = grd2["member"].values[0]
                time_str = meteva.base.tool.time_tools.all_type_time_to_str(grd2["time"].values[0])
                dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[6:8] + "日" + time_str[8:10] + "时"
                dtime_str = str(int(grd2["dtime"].values[0]))
                if subplot == ["level"]:
                    title00 =level_str
                elif subplot == ["time"]:
                    title00 = dati_str
                elif subplot == ["dtime"]:
                    title00 = dtime_str +  "H时效 "
                elif subplot == ["member"]:
                    title00 = data_name
                else:
                    title00 =data_name +"_L"+level_str+"_"+ dati_str+"_"+dtime_str+"H时效"
                title1.append(title00)

        plot_2d_grid_list(grd_list1,type = "contour",save_path= save_path,title= title1,clevs=clevs,cmap=cmap,vmax = vmax,vmin = vmin,add_county_line= add_county_line,
                      add_worldmap = add_worldmap,show=show,dpi = dpi,sup_fontsize = sup_fontsize,height= height,width = width,ncol= ncol,
                      sup_title = sup_title1,clip= clip,add_minmap=add_minmap)



def plot_2d_grid_list(grd_list,type = "contour",save_path = None,title = None,clevs= None,cmap ="rainbow",add_county_line = False,add_worldmap =False,show = False,dpi = 300,
                     sup_fontsize = 10,height = None,width = None,ncol = None,vmax = None,vmin = None, sup_title = None,clip= None,add_minmap = None):


    if save_path is None:
        show = True

    x = grd_list[0]['lon'].values
    slon = x[0]
    elon = x[-1]
    y = grd_list[0]['lat'].values
    slat = y[0]
    elat = y[-1]
    rlon = x[-1] - x[0]
    rlat = y[-1] - y[0]



    height_title = sup_fontsize * 0.1
    height_bottem_xticsk = sup_fontsize * 0.05
    height_hspace = sup_fontsize * 0.03

    width_wspace = height_hspace

    width_colorbar = 0.5
    width_left_yticks = sup_fontsize * 0.1

    nplot = len(grd_list)
    if ncol is None:
        match_list = []
        for i in range(nplot,0,-1):
            ncol = i
            nrow = int(math.ceil(len(grd_list) / ncol))
            rate = ncol * rlon/(nrow * rlat)
            if rate <2 and rate > 9/16:
                match_list.append([i,ncol * nrow - nplot])
        if len(match_list)  ==0:
            ncol = nplot
        else:
            match_array = np.array(match_list)
            min_index = np.argmin(match_array[:,1])
            ncol = match_array[min_index,0]
    nrow = int(math.ceil(nplot / ncol))

    if width is None and height is None:
        width = 8

    if width is None:
        height_all_plot = height - height_title - height_bottem_xticsk - (nrow-1) * height_hspace
        height_map = height_all_plot / nrow
        width_map = height_map * rlon / rlat
        width_all_plot = width_map * ncol + (ncol-1) * width_wspace
        width = width_all_plot + width_colorbar + width_left_yticks
    else:
        width_all_plot = width - width_colorbar - width_left_yticks - (ncol - 1) * width_wspace
        width_map = width_all_plot / ncol
        height_map = width_map * rlat / rlon
        height_all_plot = height_map * nrow + (nrow-1) * height_hspace
        height = height_all_plot + height_title + height_bottem_xticsk

    if clevs is None and vmin is None and vmax is None:
        vmax = -1e30
        vmin = 1e30
        for grd in grd_list:
            vmax1 = np.max(grd.values)
            if vmax < vmax1:
                vmax = vmax1
            vmin1 = np.min(grd.values)
            if vmin > vmin1:
                vmin = vmin1
    cmap1, clevs1 = meteva.base.tool.color_tools.def_cmap_clevs(cmap=cmap, clevs=clevs, vmin=vmin, vmax=vmax)
    norm = BoundaryNorm(clevs1, ncolors=cmap1.N-1)

    vmax = elon
    vmin = slon
    r = rlon
    if r <= 1:
        inte = 0.1
    elif r <= 5 and r > 1:
        inte = 1
    elif r <= 10 and r > 5:
        inte = 2
    elif r < 20 and r >= 10:
        inte = 4
    elif r <= 30 and r >= 20:
        inte = 5
    elif r < 180:
        inte = 10
    else:
        inte = 20

    vmin = inte * (math.ceil(vmin / inte))
    vmax = inte * ((int)(vmax / inte) + 1)

    xticks = np.arange(vmin, vmax, inte)
    xticks_label = []
    xticks_label_None = []
    for i in range(len(xticks)):
        xticks_label.append(str(round(xticks[i],6)))
        xticks_label_None.append("")
    if xticks[-1] >0:
        xticks_label[-1] ="   " +xticks_label[-1] + "°E"
    else:
        xticks_label[-1] ="   " +xticks_label[-1] + "°W"


    vmax = elat
    vmin = slat
    r = rlat
    if r <= 1:
        inte = 0.1
    elif r <= 5 and r > 1:
        inte = 1
    elif r <= 10 and r > 5:
        inte = 2
    elif r < 20 and r >= 10:
        inte = 4
    elif r <= 30 and r >= 20:
        inte = 5
    else:
        inte = 10

    vmin = inte * (math.ceil(vmin / inte))
    vmax = inte * ((int)(vmax / inte) + 1)
    yticks = np.arange(vmin, vmax, inte)
    yticks_label = []
    yticks_label_None = []
    for j in range(len(yticks)):
        if yticks[j] >= 0:
            yticks_label.append(str(round(yticks[j],6))+"°N")
        else:
            yticks_label.append(str(round(-yticks[j], 6)) +"°S")
        yticks_label_None.append("")


    if isinstance(title, list):
        if nplot != len(title):
            print("手动设置的title数目和要绘制的图形数目不一致")
            return


    fig = plt.figure(figsize=(width, height), dpi=dpi)

    for p in range(nplot):
        pi = p % ncol
        pj = int(p / ncol)
        rect1 = [(width_left_yticks + pi * (width_map + width_wspace))/width,
                 (height_bottem_xticsk + (nrow -1- pj) * (height_map + height_hspace))/height,
                 width_map / width,
                 height_map / height]
        ax = plt.axes(rect1)

        if title is None:
            try:

                time_str = meteva.base.tool.time_tools.time_to_str(grd_list[p]["time"].values[0])
                dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[6:8] + "日" + time_str[8:10] + "时"
                #print(str(grd_list[p]["dtime"].values[0]))
                title1 = str(grd_list[p]["member"].values[0]) + " " + dati_str + str(grd_list[p]["dtime"].values[0]) + "H时效 "

                if "var_name" in grd_list[p].attrs.keys():
                    title1 = title1 + grd_list[p].attrs["var_name"]
            except:
                print("time or dtime or level 格式错误，请更改相应数据格式或直接指定title")
                title1= ""
        else:
            #title1 = title.replace("NNN",data_name)
            if isinstance(title,list):
                title1 = title[p]
            else:
                title1 = title

        plt.title(title1,fontsize = sup_fontsize,pad = 0)

        if slon < 70 or elon > 140 or slat < 10 or elat > 60:
            add_worldmap = True
        if add_worldmap:
            add_china_map_2basemap(ax, name="world", edgecolor='k', lw=0.3, encoding='gbk', grid0=None)  # "国界"

        add_china_map_2basemap(ax, name="nation", edgecolor='k', lw=0.3, encoding='gbk',grid0 = None)  # "省界"
        add_china_map_2basemap(ax, edgecolor='k', lw=0.3, encoding='gbk')  # "省界"
        if add_county_line:
            add_china_map_2basemap(ax, name="county", edgecolor='k', lw=0.2, encoding='gbk', grid0=None)  # "县界"
        ax.set_xlim((slon, elon))
        ax.set_ylim((slat, elat))



        knext_row = pi + (pj + 1) * ncol
        if knext_row >= nplot:
            ax.set_xticks(xticks)
            ax.set_xticklabels(xticks_label, fontsize=sup_fontsize * 0.8, family='Times New Roman')
        else:
            ax.set_xticks(xticks)
            ax.set_xticklabels(xticks_label_None, fontsize=sup_fontsize * 0.8, family='Times New Roman')

        if pi ==0:
            ax.set_yticks(yticks)
            ax.set_yticklabels(yticks_label, fontsize=sup_fontsize * 0.8, family='Times New Roman')
        else:
            ax.set_yticks(yticks)
            ax.set_yticklabels(yticks_label_None, fontsize=sup_fontsize * 0.8, family='Times New Roman')
        if type == "contour":
            im = ax.contourf(x, y, np.squeeze(grd_list[p].values), levels=clevs1, cmap=cmap1, norm=norm)
            if clip is not None:
                try:
                    meteva.base.tool.maskout.shp2clip_by_shpfile(im, ax, clip)
                except:
                    if isinstance(clip, str): clip = [clip]
                    if isinstance(clip[0], str):
                        meteva.base.tool.maskout.shp2clip_by_region_name(im, ax, clip)
                    else:
                        meteva.base.tool.maskout.shp2clip_by_lines(im, ax, clip)

        else:
            im = ax.pcolormesh(x, y, np.squeeze(grd_list[p].values), cmap=cmap1, norm=norm)


        if add_minmap is not None:
            minmap_lon_lat = [103, 123, 0, 25]
            minmap_height_rate = 0.27
            height_bigmap = rect1[3]
            height_minmap = height_bigmap * minmap_height_rate
            width_minmap = height_minmap * (minmap_lon_lat[1] - minmap_lon_lat[0]) * height / (
                    minmap_lon_lat[3] - minmap_lon_lat[2]) / width

            width_between_two_map = height_bigmap * 0.01
            sy_minmap = width_between_two_map + rect1[1]
            if add_minmap == "left":
                sx_minmap = rect1[0] + width_between_two_map
            else:
                sx_minmap = rect1[0] + rect1[2] - width_minmap - width_between_two_map
            rect_min = [sx_minmap, sy_minmap, width_minmap, height_minmap]
            ax_min = plt.axes(rect_min)
            plt.xticks([])
            plt.yticks([])
            ax_min.set_xlim((minmap_lon_lat[0], minmap_lon_lat[1]))
            ax_min.set_ylim((minmap_lon_lat[2], minmap_lon_lat[3]))
            ax_min.spines["top"].set_linewidth(0.3)
            ax_min.spines["bottom"].set_linewidth(0.3)
            ax_min.spines["right"].set_linewidth(0.3)
            ax_min.spines["left"].set_linewidth(0.3)
            add_china_map_2basemap(ax_min, name="world", edgecolor='k', lw=0.2, encoding='gbk', grid0=None)  # "国界"
            add_china_map_2basemap(ax_min, name="nation", edgecolor='k', lw=0.2, encoding='gbk', grid0=None)  # "省界"
            #ax_min.pcolormesh(x, y, np.squeeze(grd_list[p].values), cmap=cmap1, norm=norm)



    left_low = (width_left_yticks - 0.2 + ncol * (width_map  + width_wspace))/width

    colorbar_position = fig.add_axes([left_low, height_bottem_xticsk / height,0.02, height_all_plot/height])  # 位置[左,下,宽,高]
    cb = plt.colorbar(im, cax=colorbar_position)
    cb.ax.tick_params(labelsize=sup_fontsize *0.8)  #设置色标刻度字体大小。

    y_sup_title = (height_bottem_xticsk + (nrow) * (height_map + height_hspace)) / height
    if sup_title is not None:
        plt.suptitle(sup_title, y = y_sup_title,fontsize=sup_fontsize * 1.2)

    if save_path is None:
        show = True

    if save_path is not None:
        meteva.base.tool.path_tools.creat_path(save_path)
        file1, extension = os.path.splitext(save_path)
        if(len(extension) ==0):
            print("save_path中没包含后缀，如.png等,未能输出至指定路径")
            return
        extension = extension[1:]
        plt.savefig(save_path,format = extension,bbox_inches='tight')
        print("图片已保存至" + save_path)
    if show:
        plt.show()
    plt.close()


def pcolormesh_2d_grid(grd,save_path = None,title = None,clevs= None,cmap = "rainbow",add_county_line = False,add_worldmap=False,show = False,dpi = 300,
                       sup_fontsize = 10,height = None,width = None):

    if save_path is None:
        show = True
    x = grd['lon'].values
    y = grd['lat'].values
    rlon = x[-1] - x[0]
    rlat = y[-1] - y[0]

    grid0 = meteva.base.get_grid_of_data(grd)

    if height is None:
        height = 4
    title_hight = 0.6
    legend_hight = 0.3
    left_plots_width  = 0.8
    right_plots_width = 0.8
    if width is None:
        width = (height - title_hight - legend_hight) * rlon / rlat + left_plots_width + right_plots_width



    fig = plt.figure(figsize=(width, height),dpi = dpi)
    rect1 = [left_plots_width / width, legend_hight/height, (width - right_plots_width - left_plots_width) / width, 1-title_hight/height]
    ax = plt.axes(rect1)



    if title is None:
        time_str = meteva.base.tool.time_tools.time_to_str(grid0.gtime[0])
        dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[6:8] + "日" + time_str[8:10] + "时"
        if type(grid0.members[0]) == str:
            model_name = grid0.members[0]
        else:
            model_name = str(grid0.members[0])
        title = model_name + " "+dati_str  + str(grid0.dtimes[0]) + "H时效 " + grd.name
    plt.title(title,fontsize = 14)
    grid0 = meteva.base.get_grid_of_data(grd)


    if grid0.slon < 70 or grid0.elon > 140 or grid0.slat < 10 or grid0.elat > 60:
        add_worldmap = True
    if add_worldmap:
        add_china_map_2basemap(ax, name="world", edgecolor='k', lw=0.3, encoding='gbk', grid0=None)  # "国界"

    add_china_map_2basemap(ax, name="nation", edgecolor='k', lw=0.3, encoding='gbk')  # "国界"
    add_china_map_2basemap(ax,  edgecolor='k', lw=0.3, encoding='gbk')   # "省界"

    if add_county_line:
        add_china_map_2basemap(ax, name="county", edgecolor='k', lw=0.2, encoding='gbk')  # "县界"

    ax.set_xlim((grid0.slon, grid0.elon))
    ax.set_ylim((grid0.slat, grid0.elat))


    vmax = np.max(grd.values)
    vmin = np.min(grd.values)
    cmap1,clevs1 = meteva.base.tool.color_tools.def_cmap_clevs(cmap=cmap,clevs=clevs,vmin=vmin,vmax = vmax)

    norm = BoundaryNorm(clevs1, ncolors=cmap1.N-1)
    im = ax.pcolormesh(x, y, np.squeeze(grd.values), cmap=cmap1,norm=norm)
    #im = ax.contourf(x,y,np.squeeze(grd.values))
    left_low = (width + 0.1 - right_plots_width) / width
    colorbar_position = fig.add_axes([left_low, legend_hight / height, 0.02, 1-title_hight/height])  # 位置[左,下,宽,高]
    plt.colorbar(im,cax= colorbar_position)




    vmax = x[-1]
    vmin = x[0]
    r = rlon
    if r <= 1:
        inte = 0.1
    elif r <= 5 and r > 1:
        inte = 1
    elif r <= 10 and r > 5:
        inte = 2
    elif r < 20 and r >= 10:
        inte = 4
    elif r <= 30 and r >= 20:
        inte = 5
    elif r <180:
        inte = 10
    else:
        inte = 20

    vmin = inte * (math.ceil(vmin / inte))
    vmax = inte * ((int)(vmax / inte)+1)
    xticks = np.arange(vmin,vmax,inte)
    xticks_label = []
    for x in range(len(xticks)):
        xticks_label.append(str(round(xticks[x],6)))
    if xticks[-1] >0:
        xticks_label[-1] ="   " +xticks_label[-1] + "°E"
    else:
        xticks_label[-1] ="   " +xticks_label[-1] + "°W"
    ax.set_xticks(xticks)
    ax.set_xticklabels(xticks_label,fontsize = sup_fontsize * 0.9, family='Times New Roman')

    vmax = y[-1]
    vmin = y[0]
    r = rlat
    if r <= 1:
        inte = 0.1
    elif r <= 5 and r > 1:
        inte = 1
    elif r <= 10 and r > 5:
        inte = 2
    elif r < 20 and r >= 10:
        inte = 4
    elif r <= 30 and r >= 20:
        inte = 5
    else:
        inte = 10

    vmin = inte * (math.ceil(vmin / inte))
    vmax = inte * ((int)(vmax / inte)+1)
    yticks = np.arange(vmin,vmax,inte)
    yticks_label = []
    for y in range(len(yticks)):
        if yticks[y] >= 0:
            yticks_label.append(str(round(yticks[y],6))+"°N")
        else:
            yticks_label.append(str(round(-yticks[y], 6)) +"°S")
    ax.set_yticks(yticks)
    ax.set_yticklabels(yticks_label,fontsize = sup_fontsize * 0.9, family='Times New Roman')


    if(save_path is not None):
        file1,extension = os.path.splitext(save_path)
        extension = extension[1:]
        plt.savefig(save_path,format = extension,bbox_inches='tight')
    else:
        show = True
    if show:
        plt.show()
    plt.close()



def scatter_sta(sta0,value_column=None,
                map_extend = None,add_county_line = False,add_worldmap = False,
                clevs=None, cmap="rainbow",
                fix_size = True,threshold = None,mean_value = None,
                print_max = 0,print_min = 0,save_dir = None,
                save_path=None,show = False,dpi = 300,title=None,
                sup_fontsize = 10,
                height = None,width = None,
                min_spot_value = 0,grid = False,subplot = None,ncol = None,point_size = None,sup_title = None,add_minmap = None,title_in_ax = False):

    sta = sta0
    if save_path is None and save_dir is None:
        show = True
    if isinstance(map_extend,list):
        slon = map_extend[0]
        elon = map_extend[1]
        slat = map_extend[2]
        elat = map_extend[3]
        rlon = elon - slon
        rlat = elat - slat
    elif isinstance(map_extend,meteva.base.grid):
        slon = map_extend.slon
        slat = map_extend.slat
        elon = map_extend.elon
        elat = map_extend.elat
        rlon = map_extend.elon - map_extend.slon
        rlat = map_extend.elat - map_extend.slat
    else:
        slon0 = np.min(sta.loc[:,"lon"].values)
        slat0 = np.min(sta.loc[:,"lat"].values)
        elon0 = np.max(sta.loc[:,"lon"].values)
        elat0 = np.max(sta.loc[:,"lat"].values)
        if elon0>180:
            sta = sta0.copy()
            sta.loc[sta0["lon"] > 180,"lon"] = sta0.loc[sta0["lon"] > 180,"lon"] - 360
            slon0 = np.min(sta.loc[:, "lon"].values)
            elon0 = np.max(sta.loc[:, "lon"].values)

        dlon0 = (elon0 - slon0) * 0.03
        if dlon0 >1:
            dlon0 = 1
        dlat0 = (elon0 - slon0) * 0.03
        if dlat0 >1:
            dlat0 = 1
        slon = slon0 - dlon0
        elon = elon0 + dlon0
        slat = slat0 - dlat0
        elat = elat0 + dlat0
        rlon = elon - slon
        rlat = elat - slat


    if height is None:
        height = 4
    title_hight = 1.0
    legend_hight = 0.3
    left_plots_width  = 0.8
    right_plots_width = 0.8
    if width is None:
        width = (height - title_hight - legend_hight) * rlon / rlat + left_plots_width + right_plots_width
    map_width = width - left_plots_width - right_plots_width
    map_area = (height - title_hight - legend_hight) *map_width

    data_names = meteva.base.get_stadata_names(sta)
    #value_column为指定绘制的数据列。 如果不知道绘制某一列就绘制所有列
    if value_column is None:
        plot_data_names = data_names
        value_column = 0
    else:
        plot_data_names = [data_names[value_column]]
        data_names = plot_data_names
        #print(plot_data_names)

    sta_without_iv = meteva.base.sele.not_IV(sta)

    values = sta_without_iv.loc[:, plot_data_names].values
    if mean_value is None:
        mean_value = np.sum(np.abs(values)) / values.size

    vmax_v = np.max(sta_without_iv[plot_data_names].values)
    vmin_v = np.min(sta_without_iv[plot_data_names].values)

    cmap1,clevs1 = meteva.base.tool.color_tools.def_cmap_clevs(cmap=cmap,clevs=clevs,vmin=vmin_v,vmax = vmax_v)
    #clevs1, cmap1 = meteva.base.tool.color_tools.def_cmap_clevs(clevs=clevs, cmap=cmap, vmin = None, vmax=None)
    #meteva.base.tool.color_tools.show_cmap_clev(cmap1,clevs1)

    norm = BoundaryNorm(clevs1, ncolors=cmap1.N-1)



    if point_size is None:

        sta_id1 = sta0.drop_duplicates(['id'])
        sta_dis = meteva.base.sta_dis_ensemble_near_by_sta(sta_id1,nearNum=2)
        dis_values = sta_dis["data1"].values
        dis_values.sort()
        dis1 = dis_values[int(len(dis_values) * 0.02) + 1]
        point_size = (map_width * dis1 / rlon)**2
        if (point_size > 50): point_size = 50
        if (point_size < 0.1): point_size = 0.1
        #point_size *=3
    left_low = (width + 0.1 - right_plots_width) / width


    vmax = elon
    vmin = slon
    r = rlon
    if r <= 1:
        inte = 0.1
    elif r <= 5 and r > 1:
        inte = 1
    elif r <= 10 and r > 5:
        inte = 2
    elif r < 20 and r >= 10:
        inte = 4
    elif r <= 30 and r >= 20:
        inte = 5
    elif r <180:
        inte = 10
    else:
        inte = 20

    vmin = inte * (math.ceil(vmin / inte))
    vmax = inte * ((int)(vmax / inte) + 1)

    xticks = np.arange(vmin, vmax, inte)
    xticks_label = []
    for x in range(len(xticks)):
        xticks_label.append(str(round(xticks[x],6)))
    if xticks[-1] >0:
        xticks_label[-1] ="   " +xticks_label[-1] + "°E"
    else:
        xticks_label[-1] ="   " +xticks_label[-1] + "°W"


    vmax = elat
    vmin = slat
    r = rlat
    if r <= 1:
        inte = 0.1
    elif r <= 5 and r > 1:
        inte = 1
    elif r <= 10 and r > 5:
        inte = 2
    elif r < 20 and r >= 10:
        inte = 4
    elif r <= 30 and r >= 20:
        inte = 5
    else:
        inte = 10

    vmin = inte * (math.ceil(vmin / inte))
    vmax = inte * ((int)(vmax / inte) + 1)
    yticks = np.arange(vmin, vmax, inte)
    yticks_label = []
    for y in range(len(yticks)):
        if yticks[y] >= 0:
            yticks_label.append(str(round(yticks[y],6))+"°N")
        else:
            yticks_label.append(str(round(-yticks[y], 6)) +"°S")


    if subplot is None:

        split = ["level","time","dtime","member"]
        sta_list = meteva.base.split(sta0,used_coords=split)
        nplot = len(sta_list)
        #nplot = len(plot_data_names)
        if isinstance(title, list):
            if nplot != len(title):
                print("手动设置的title数目和要绘制的图形数目不一致")
                return
        if save_path is not None:
            if isinstance(save_path,str):
                save_path = [save_path]
            if nplot != len(save_path):
                print("手动设置的save_path数目和要绘制的图形数目不一致")
                return

        for p in range(nplot):
            #data_name = data_names[p]
            #sta_one_member = meteva.base.sele_by_para(sta,member=[data_name],drop_IV=True)
            sta_one_member = sta_list[p]
            data_name = meteva.base.get_stadata_names(sta_one_member)[0]
            #print(sta_one_member)
            x = sta_one_member.loc[:, "lon"].values
            y = sta_one_member.loc[:, "lat"].values
            value = sta_one_member.loc[:, data_name].values
            fig = plt.figure(figsize=(width, height),dpi = dpi)
            rect1 = [left_plots_width / width, legend_hight / height, (width - right_plots_width - left_plots_width) / width,
                     1 - title_hight / height]
            ax = plt.axes(rect1)


            if title is None:
                try:
                    time_str = meteva.base.tool.time_tools.time_to_str(sta_one_member.iloc[0, 1])
                    dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[6:8] + "日" + time_str[8:10] + "时"
                    level_str = str(int(sta_one_member.iloc[0, 0]))
                    title1 = data_name + "_L"+level_str+"_" + dati_str + str(sta_one_member.iloc[0,2]) + "H时效"
                except:
                    print("time or dtime or level 格式错误，请更改相应数据格式或直接指定title")
                    title1= ""
            else:
                #title1 = title.replace("NNN",data_name)
                if isinstance(title,list):
                    title1 = title[p]
                else:
                    title1 = title +"(" +data_name+")"

            plt.title(title1,fontsize = sup_fontsize)

            if slon < 70 or elon > 140 or slat < 10 or elat > 60:
                add_worldmap = True
            if add_worldmap:
                add_china_map_2basemap(ax, name="world", edgecolor='k', lw=0.3, encoding='gbk', grid0=None)  # "国界"


            add_china_map_2basemap(ax, name="nation", edgecolor='k', lw=0.3, encoding='gbk',grid0 = None)  # "省界"
            add_china_map_2basemap(ax, edgecolor='k', lw=0.3, encoding='gbk')  # "省界"
            if add_county_line:
                add_china_map_2basemap(ax, name="county", edgecolor='k', lw=0.2, encoding='gbk', grid0=None)  # "县界"
            ax.set_xlim((slon, elon))
            ax.set_ylim((slat, elat))
            colors = value
            if isinstance(fix_size,bool):
                if fix_size:
                    im = ax.scatter(x, y, c=colors, cmap=cmap1, norm=norm, s=point_size,edgecolors ="face")
                else:
                    area = point_size * np.abs(value - min_spot_value)/mean_value
                    if(threshold is not None):
                        area[np.abs(value- min_spot_value)<threshold] *= 0.1
                    im = ax.scatter(x, y, c=colors, cmap=cmap1, norm=norm, s=area)
                    if grid:plt.grid()
            else:
                im = ax.scatter(x, y, c=colors, cmap=cmap1, norm=norm, s=fix_size)

            if print_max>0:
                print("取值最大的"+str(print_max)+"个站点：")
                indexs = value.argsort()[-print_max:][::-1]
                for index in indexs:
                    print("id:" + str(sta_one_member.iloc[index,3]) +"   lon:"+str(sta_one_member.iloc[index,4])+"  lat:" + str(sta_one_member.iloc[index,5]) +
                          " value:"+str(sta_one_member.iloc[index,6]))
            if print_min>0:
                print("取值最小的"+str(print_min)+"个站点：")
                indexs = value.argsort()[:print_min]
                for index in indexs:
                    print("id:" + str(sta_one_member.iloc[index,3]) +"   lon:"+str(sta_one_member.iloc[index,4])+"  lat:" + str(sta_one_member.iloc[index,5]) +
                          " value:"+str(sta_one_member.iloc[index,6]))

            colorbar_position = fig.add_axes([left_low, legend_hight / height, 0.02, 1-title_hight/height])  # 位置[左,下,宽,高]
            plt.colorbar(im, cax=colorbar_position)


            ax.set_xticks(xticks)
            ax.set_xticklabels(xticks_label,fontsize = sup_fontsize * 0.8, family='Times New Roman')

            ax.set_yticks(yticks)
            ax.set_yticklabels(yticks_label,fontsize = sup_fontsize * 0.8, family='Times New Roman')

            if slon< 75 and elon >130 and elat >50 and slat >3 and slat <25:
                if add_minmap is None:
                    add_minmap = "left"

            if add_minmap is not None:
                minmap_lon_lat = [103, 123, 0, 25]
                minmap_height_rate = 0.27
                height_bigmap = rect1[3]
                height_minmap = height_bigmap * minmap_height_rate
                width_minmap = height_minmap * (minmap_lon_lat[1] - minmap_lon_lat[0]) * height / (
                        minmap_lon_lat[3] - minmap_lon_lat[2]) / width

                width_between_two_map = height_bigmap * 0.01
                sy_minmap = width_between_two_map + rect1[1]
                if add_minmap == "left":
                    sx_minmap = rect1[0] + width_between_two_map
                else:
                    sx_minmap = rect1[0] + rect1[2] - width_minmap - width_between_two_map
                rect_min = [sx_minmap, sy_minmap, width_minmap, height_minmap]
                ax_min = plt.axes(rect_min)
                plt.xticks([])
                plt.yticks([])
                ax_min.set_xlim((minmap_lon_lat[0], minmap_lon_lat[1]))
                ax_min.set_ylim((minmap_lon_lat[2], minmap_lon_lat[3]))
                ax_min.spines["top"].set_linewidth(0.3)
                ax_min.spines["bottom"].set_linewidth(0.3)
                ax_min.spines["right"].set_linewidth(0.3)
                ax_min.spines["left"].set_linewidth(0.3)
                add_china_map_2basemap(ax_min, name="world", edgecolor='k', lw=0.2, encoding='gbk', grid0=None)  # "国界"
                add_china_map_2basemap(ax_min, name="nation", edgecolor='k', lw=0.2, encoding='gbk', grid0=None)  # "省界"



            save_path1 = None
            if save_path is None:
                if save_dir is None:
                    show = True
                else:
                    save_path1 = save_dir + "/" + title1 + ".png"
            else:
                save_path1 = save_path[p]
            if save_path1 is not None:
                meteva.base.tool.path_tools.creat_path(save_path1)
                file1, extension = os.path.splitext(save_path1)
                if(len(extension) ==0):
                    print("save_path中没包含后缀，如.png等,未能输出至指定路径")
                    return
                extension = extension[1:]
                plt.savefig(save_path1,format = extension,bbox_inches='tight')
                print("图片已保存至" + save_path1)
            if show:
                plt.show()
            plt.close()


    else:
        split = ["level","time","dtime","member"]
        if not isinstance(subplot,list):
            subplot = [subplot]
        for s in subplot:
            split.remove(s)
        sta_list = meteva.base.split(sta0,used_coords=split)
        ng = len(sta_list)

        if sup_title is None:
            sup_title = []
            for i in range(ng):
                sta0 = sta_list[i]
                if subplot==["level"]:
                    data_names = meteva.base.get_stadata_names(sta0)
                    time_str = meteva.base.tool.time_tools.time_to_str(sta0.iloc[0, 1])
                    dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[6:8] + "日" + time_str[8:10] + "时"
                    sup_title1 = data_names[0] + "_" + dati_str + str(sta0.iloc[0, 2]) + "H时效"
                elif subplot==["time"]:
                    data_names = meteva.base.get_stadata_names(sta0[0])
                    level_str = str(int(sta0.iloc[0, 0]))
                    sup_title1 = data_names[0] + "_Level" + level_str + "_"+ str(sta0.iloc[0, 2]) + "H时效"
                elif subplot ==["dtime"]:
                    data_names = meteva.base.get_stadata_names(sta0)
                    time_str = meteva.base.tool.time_tools.time_to_str(sta0.iloc[0, 1])
                    level_str = str(int(sta0.iloc[0, 0]))
                    dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[6:8] + "日" + time_str[8:10] + "时"
                    sup_title1 = data_names[0] + "_Level"+ level_str + "_" + dati_str
                elif subplot ==["member"]:
                    time_str = meteva.base.tool.time_tools.time_to_str(sta0.iloc[0, 1])
                    level_str = str(int(sta0.iloc[0, 0]))
                    dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[6:8] + "日" + time_str[8:10] + "时"
                    sup_title1 = " Level" + level_str + "_"+ dati_str+ str(sta0.iloc[0, 2]) + "H时效"
                else:
                    sup_title1 = "none"

                sup_title.append(sup_title1)
        else:
            if not isinstance(sup_title,list):
                sup_title2 = []
                for i in range(ng):
                    sup_title2.append(sup_title)
                sup_title = sup_title2
            if len(sup_title) != ng:
                print("sup_title的数目应该和最终生成的图片数目一致")
                return

        for n in range(ng):
            sta1 = sta_list[n]
            sta_g1  = meteva.base.split(sta1,used_coords = subplot)
            ng1 = len(sta_g1)
            if isinstance(title,list):
                title1 = title[(ng1 * n):(ng1 * (n+1))]
            else:
                title1 = []
                for  kk in range(len(sta_g1)):
                    sta0 = sta_g1[kk]
                    if subplot==["level"]:
                        title00 = str(int(sta0.iloc[0, 0]))
                    elif subplot==["time"]:
                        time_str = meteva.base.tool.time_tools.time_to_str(sta0.iloc[0, 1])
                        title00 = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[6:8] + "日" + time_str[8:10] + "时"
                    elif subplot ==["dtime"]:
                        title00 =str(sta0.iloc[0, 2]) + "H时效 "
                    elif subplot ==["member"]:
                        data_names = meteva.base.get_stadata_names(sta0)
                        title00 = data_names[0]
                    else:
                        title00 = "none"
                    title1.append(title00)



            if isinstance(save_path,list):
                save_path1 = save_path[n]
            elif save_path is not None:
                save_path1 = save_path
            elif save_dir is not None:
                save_path1 = save_dir+"/"+sup_title[n]+".png"

            else:
                save_path1 = None



            scatter_sta_list(sta_g1,map_extend = map_extend,add_county_line = add_county_line,
            add_worldmap=add_worldmap,clevs = clevs,cmap = cmap,vmax=vmax_v,vmin = vmin_v,fix_size=fix_size,threshold=threshold,
                             mean_value = mean_value,save_path = save_path1,show = show,dpi = dpi,
                            title = title1,sup_fontsize = sup_fontsize,
                             height=height,width= width,min_spot_value=min_spot_value,grid = grid,ncol = ncol,point_size=point_size,sup_title=sup_title[n],
                             add_minmap = add_minmap,print_max = print_max,print_min = print_min,title_in_ax=title_in_ax)


def scatter_sta_list(sta0_list,map_extend = None,add_county_line = False,add_worldmap = False,
                clevs=None, cmap="rainbow",vmax = None,vmin = None,
                fix_size = True,threshold = None,mean_value = None,
                save_path=None,show = False,dpi = 300,title = None,
                sup_fontsize = 10,
                height = None,width = None,
                min_spot_value = 0,grid = False,ncol = None,point_size = None,sup_title = None,add_minmap = None,print_max = 0,print_min = 0,
                     title_in_ax = False):

    sta0 = sta0_list[0]
    if isinstance(map_extend, list):
        slon = map_extend[0]
        elon = map_extend[1]
        slat = map_extend[2]
        elat = map_extend[3]
        rlon = elon - slon
        rlat = elat - slat
    elif isinstance(map_extend, meteva.base.grid):
        slon = map_extend.slon
        slat = map_extend.slat
        elon = map_extend.elon
        elat = map_extend.elat
        rlon = map_extend.elon - map_extend.slon
        rlat = map_extend.elat - map_extend.slat
    else:
        slon0 = np.min(sta0.loc[:, "lon"].values)
        slat0 = np.min(sta0.loc[:, "lat"].values)
        elon0 = np.max(sta0.loc[:, "lon"].values)
        elat0 = np.max(sta0.loc[:, "lat"].values)
        if elon0 > 180:
            sta = sta0.copy()
            sta.loc[sta0["lon"] > 180, "lon"] = sta0.loc[sta0["lon"] > 180, "lon"] - 360
            slon0 = np.min(sta.loc[:, "lon"].values)
            elon0 = np.max(sta.loc[:, "lon"].values)

        dlon0 = (elon0 - slon0) * 0.03
        if dlon0 > 1:
            dlon0 = 1
        dlat0 = (elon0 - slon0) * 0.03
        if dlat0 > 1:
            dlat0 = 1
        slon = slon0 - dlon0
        elon = elon0 + dlon0
        slat = slat0 - dlat0
        elat = elat0 + dlat0
        rlon = elon - slon
        rlat = elat - slat

    if sup_title is None:
        sup_height_title = 0
    else:
        sup_height_title = sup_fontsize * 0.12

    height_title = sup_fontsize * 0.1
    height_bottem_xticsk = sup_fontsize * 0.05
    height_hspace = sup_fontsize * 0.03

    width_wspace = height_hspace

    width_colorbar = 0.5
    width_left_yticks = sup_fontsize * 0.1

    nplot = len(sta0_list)
    if ncol is None:
        match_list = []
        for i in range(nplot,0,-1):
            ncol = i
            nrow = int(math.ceil(len(sta0_list) / ncol))
            rate = ncol * rlon/(nrow * rlat)
            if rate <2 and rate > 9/16:
                match_list.append([i,ncol * nrow - nplot])
        if len(match_list)  ==0:
            ncol = nplot
        else:
            match_array = np.array(match_list)
            min_index = np.argmin(match_array[:,1])
            ncol = match_array[min_index,0]
    nrow = int(math.ceil(nplot / ncol))

    if width is None and height is None:
        width = 8

    if width is None:
        height_all_plot = height - height_title - height_bottem_xticsk - (nrow-1) * height_hspace + sup_height_title
        height_map = height_all_plot / nrow
        width_map = height_map * rlon / rlat
        width_all_plot = width_map * ncol + (ncol-1) * width_wspace
        width = width_all_plot + width_colorbar + width_left_yticks
    else:
        width_all_plot = width - width_colorbar - width_left_yticks - (ncol - 1) * width_wspace
        width_map = width_all_plot / ncol
        height_map = width_map * rlat / rlon
        height_all_plot = height_map * nrow + (nrow-1) * height_hspace
        height = height_all_plot + height_title + height_bottem_xticsk + sup_height_title


    map_area = height_map *width_map

    cmap1, clevs1 = meteva.base.tool.color_tools.def_cmap_clevs(cmap=cmap, clevs=clevs, vmin=vmin, vmax=vmax)

    norm = BoundaryNorm(clevs1, ncolors=cmap1.N-1)
    #print(sta0_list[0])
    if point_size is None:

        sta_id1 = sta0.drop_duplicates(['id'])
        sta_dis = meteva.base.sta_dis_ensemble_near_by_sta(sta_id1,nearNum=2)
        dis_values = sta_dis["data1"].values
        dis_values.sort()
        dis1 = dis_values[int(len(dis_values) * 0.02) + 1]
        point_size = (width_map * dis1 / rlon)**2
        if (point_size > 50): point_size = 50
        if (point_size < 0.1): point_size = 0.1


        #point_size = int(100 * map_area / len(sta0_list[0].index))
        #if (point_size > 50): point_size = 50
        #if (point_size < 1): point_size = 1
        #point_size *=1.5


    vmax = elon
    vmin = slon
    r = rlon
    if r <= 1:
        inte = 0.1
    elif r <= 5 and r > 1:
        inte = 1
    elif r <= 10 and r > 5:
        inte = 2
    elif r < 20 and r >= 10:
        inte = 4
    elif r <= 30 and r >= 20:
        inte = 5
    elif r < 180:
        inte = 10
    else:
        inte = 20

    vmin = inte * (math.ceil(vmin / inte))
    vmax = inte * ((int)(vmax / inte) + 1)

    xticks = np.arange(vmin, vmax, inte)
    xticks_label = []
    xticks_label_None = []
    for x in range(len(xticks)):
        xticks_label.append(str(round(xticks[x],6)))
        xticks_label_None.append("")
    if xticks[-1] >0:
        xticks_label[-1] ="   " +xticks_label[-1] + "°E"
    else:
        xticks_label[-1] ="   " +xticks_label[-1] + "°W"


    vmax = elat
    vmin = slat
    r = rlat
    if r <= 1:
        inte = 0.1
    elif r <= 5 and r > 1:
        inte = 1
    elif r <= 10 and r > 5:
        inte = 2
    elif r < 20 and r >= 10:
        inte = 4
    elif r <= 30 and r >= 20:
        inte = 5
    else:
        inte = 10

    vmin = inte * (math.ceil(vmin / inte))
    vmax = inte * ((int)(vmax / inte) + 1)
    yticks = np.arange(vmin, vmax, inte)
    yticks_label = []
    yticks_label_None = []
    for y in range(len(yticks)):
        if yticks[y] >= 0:
            yticks_label.append(str(round(yticks[y],6))+"°N")
        else:
            yticks_label.append(str(round(-yticks[y], 6)) +"°S")
        yticks_label_None.append("")


    if isinstance(title, list):
        if nplot != len(title):
            print("手动设置的title数目和要绘制的图形数目不一致")
            return


    fig = plt.figure(figsize=(width, height), dpi=dpi)
    title1 = None
    for p in range(nplot):
        sta_one_member = meteva.base.sele_by_para(sta0_list[p],drop_IV=True)
        data_name = meteva.base.get_stadata_names(sta_one_member)

        x = sta_one_member.loc[:, "lon"].values
        y = sta_one_member.loc[:, "lat"].values
        value = sta_one_member.loc[:, data_name].values.squeeze()

        pi = p % ncol
        pj = int(p / ncol)



        rect1 = [(width_left_yticks + pi * (width_map + width_wspace))/width,
                 (height_bottem_xticsk + (nrow -1- pj) * (height_map + height_hspace))/height,
                 width_map / width,
                 height_map / height]
        ax = plt.axes(rect1)

        if title is None:
            try:
                time_str = meteva.base.tool.time_tools.time_to_str(sta_one_member.iloc[0, 1])
                dati_str = time_str[0:4] + "年" + time_str[4:6] + "月" + time_str[6:8] + "日" + time_str[8:10] + "时"
                title1 = data_name[0] + " " + dati_str + str(sta_one_member.iloc[0,2]) + "H时效 "
            except:
                print("time or dtime or level 格式错误，请更改相应数据格式或直接指定title")
                title1= ""
        else:
            #title1 = title.replace("NNN",data_name)
            if isinstance(title,list):
                title1 = title[p]
            else:
                title1 = title

        if title_in_ax:
            ix = slon + 0.02 * (elon - slon) * 5 / width_map
            iy = elat - 0.035 * (elat - slat) * 5 / height_map
            plt.text(ix, iy, title1, bbox=dict(fc='white', ec='white', pad=0), fontsize=sup_fontsize,
                     zorder=100)
        else:
            plt.title(title1, fontsize=sup_fontsize, pad=0)


        if slon < 70 or elon > 140 or slat < 10 or elat > 60:
            add_worldmap = True
        if add_worldmap:
            add_china_map_2basemap(ax, name="world", edgecolor='k', lw=0.3, encoding='gbk', grid0=None)  # "国界"


        add_china_map_2basemap(ax, name="nation", edgecolor='k', lw=0.3, encoding='gbk',grid0 = None)  # "省界"
        add_china_map_2basemap(ax, edgecolor='k', lw=0.3, encoding='gbk')  # "省界"
        if add_county_line:
            add_china_map_2basemap(ax, name="county", edgecolor='k', lw=0.2, encoding='gbk', grid0=None)  # "县界"
        ax.set_xlim((slon, elon))
        ax.set_ylim((slat, elat))
        colors = value
        if isinstance(fix_size, bool):
            if fix_size:
                im = ax.scatter(x, y, c=colors, cmap=cmap1, norm=norm, s=point_size)
            else:

                area = point_size * np.abs(value - min_spot_value)/mean_value
                if(threshold is not None):
                    area[np.abs(value- min_spot_value)<threshold] *= 0.1
                im = ax.scatter(x, y, c=colors, cmap=cmap1, norm=norm, s=area)
                if grid:plt.grid()
        else:
            im = ax.scatter(x, y, c=colors, cmap=cmap1, norm=norm, s=fix_size)


        knext_row = pi + (pj + 1) * ncol
        if knext_row >= nplot:
            ax.set_xticks(xticks)
            ax.set_xticklabels(xticks_label, fontsize=sup_fontsize * 0.8, family='Times New Roman')
        else:
            ax.set_xticks(xticks)
            ax.set_xticklabels(xticks_label_None, fontsize=sup_fontsize * 0.8, family='Times New Roman')

        if pi ==0:
            ax.set_yticks(yticks)
            ax.set_yticklabels(yticks_label, fontsize=sup_fontsize * 0.8, family='Times New Roman')
        else:
            ax.set_yticks(yticks)
            ax.set_yticklabels(yticks_label_None, fontsize=sup_fontsize * 0.8, family='Times New Roman')

        if slon< 75 and elon >130 and elat >50 and slat >3 and slat <25:
            if add_minmap is None:
                add_minmap = "left"
        if add_minmap is not None:
            minmap_lon_lat = [105, 123, 0, 20]
            minmap_height_rate = 0.27
            height_bigmap = rect1[3]
            height_minmap = height_bigmap * minmap_height_rate
            width_minmap = height_minmap * (minmap_lon_lat[1] - minmap_lon_lat[0]) * height / (
                        minmap_lon_lat[3] - minmap_lon_lat[2])/width

            width_between_two_map =  height_bigmap *0.01
            sy_minmap = width_between_two_map + rect1[1]
            if add_minmap =="left":
                sx_minmap = rect1[0] + width_between_two_map
            else:
                sx_minmap = rect1[0] + rect1[2] - width_minmap - width_between_two_map
            rect_min = [sx_minmap,sy_minmap,width_minmap,height_minmap]
            ax_min = plt.axes(rect_min)
            plt.xticks([])
            plt.yticks([])
            ax_min.set_xlim((minmap_lon_lat[0], minmap_lon_lat[1]))
            ax_min.set_ylim((minmap_lon_lat[2], minmap_lon_lat[3]))
            ax_min.spines["top"].set_linewidth(0.3)
            ax_min.spines["bottom"].set_linewidth(0.3)
            ax_min.spines["right"].set_linewidth(0.3)
            ax_min.spines["left"].set_linewidth(0.3)
            add_china_map_2basemap(ax_min, name="world", edgecolor='k', lw=0.2, encoding='gbk', grid0=None)  # "国界"
            add_china_map_2basemap(ax_min, name="nation", edgecolor='k', lw=0.2, encoding='gbk', grid0=None)  # "省界"

        #if print_max >0 or print_min >0:
        #    print(title1)
        if print_max > 0:
            print("取值最大的" + str(print_max) + "个站点：")
            indexs = value.argsort()[-print_max:][::-1]
            for index in indexs:
                print("id:" + str(sta_one_member.iloc[index, 3]) + "   lon:" + str(
                    sta_one_member.iloc[index, 4]) + "  lat:" + str(sta_one_member.iloc[index, 5]) +
                      " value:" + str(sta_one_member.iloc[index, 6]))

        if print_min > 0:
            print("取值最小的" + str(print_min) + "个站点：")
            indexs = value.argsort()[:print_min]
            for index in indexs:
                print("id:" + str(sta_one_member.iloc[index, 3]) + "   lon:" + str(
                    sta_one_member.iloc[index, 4]) + "  lat:" + str(sta_one_member.iloc[index, 5]) +
                      " value:" + str(sta_one_member.iloc[index, 6]))
        if print_max > 0 or print_min > 0:
            print("______________")

    left_low = (width_left_yticks + ncol * (width_map  + width_wspace))/width
    colorbar_position = fig.add_axes([left_low, height_bottem_xticsk / height,0.02, height_all_plot/height])  # 位置[左,下,宽,高]

    cb = plt.colorbar(im, cax=colorbar_position)
    cb.ax.tick_params(labelsize=sup_fontsize *0.8)  #设置色标刻度字体大小。


    title1_list = [""]
    if title1 is not None:
        title1_list = title1.split("\n")


    y_sup_title = (height_bottem_xticsk + (nrow) * (height_map + height_hspace)+(len(title1_list)-1)* sup_fontsize*0.015) / height
    if sup_title is not None:
        plt.suptitle(sup_title, y = y_sup_title,fontsize=sup_fontsize * 1.2)

    if save_path is None:
        show = True

    if save_path is not None:
        meteva.base.tool.path_tools.creat_path(save_path)
        file1, extension = os.path.splitext(save_path)
        if(len(extension) ==0):
            print("save_path中没包含后缀，如.png等,未能输出至指定路径")
            return
        extension = extension[1:]
        plt.savefig(save_path,format = extension,bbox_inches='tight')
        print("图片已保存至" + save_path)
    if show:
        plt.show()
    plt.close()




def set_plot_IV(dat0):
    num = len(dat0)
    dat = np.zeros_like(dat0)
    dat[:] = dat0[:]
    if dat[0] == IV:
        dat[0] = 0
        for i in range(1,num):
            if dat0[i] != IV:
                dat[0] = dat0[i]
                break
    if dat[-1] == IV:
        dat[-1] = 0
        for i in range(num-2,-1,-1):
            if dat0[i] != IV:
                dat[-1] = dat0[i]
                break
    for i in range(1,num-1):
        if dat[i] == IV:
            i1 = 0
            for p in range(num):
                if dat[i - p] != IV:
                    i1 = i - p
                    break
            i2 = num - 1
            for p in range(num):
                if dat[i + p] != IV:
                    i2 = i + p
                    break
            rate = (i- i1) / (i2 - i1)
            dat[i] = dat[i1] * (1-rate) + dat[i2] * rate
    return dat


def set_plot_IV_with_out_start_end(dat0):
    num = len(dat0)
    dat = np.zeros_like(dat0)
    dat[:] = dat0[:]

    for i in range(1,num-1):
        if dat[i] == IV:
            i1 = i
            for p in range(1,num):
                i1 = i-p
                if i1<0 or dat[i1] != IV:
                    break
            i2 = i
            for p in range(1,num):
                i2 = i + p
                if i2>= num or dat[i2] != IV:
                    break
            if i1<0 or i2 >=num:continue
            rate = (i- i1) / (i2 - i1)
            dat[i] = dat[i1] * (1-rate) + dat[i2] * rate
    dat[dat == IV] = np.nan
    return dat

def caculate_str_width(str1,fontsize):
    max_lenght = 0
    xtick_1lines = str1.split("\n")
    for xtick1 in xtick_1lines[:2]:
        lenght = 0
        for ch in xtick1:
            if '\u4e00' <= ch <= '\u9fff':
                lenght += 2
            else:
                lenght += 1
        if max_lenght < lenght:
            max_lenght = lenght
    width =  max_lenght  * fontsize / 144
    return width

def caculate_axis_width(xticks,fontsize,legend_num = 1):
    '''
    计算绘图框的宽度
    :param xticks:
    :param fontsize:
    :param legend_num:
    :return:
    '''
    max_lenght = 0

    for i in range(len(xticks)):
        xtick = xticks[i]
        if not type(xtick) == str:
            xtick = str(xtick)
        xtick_1lines = xtick.split("\n")
        for xtick1 in xtick_1lines[:2]:
            lenght = 0
            for ch in xtick1:
                if '\u4e00' <= ch <= '\u9fff':
                    lenght += 2
                else:
                    lenght += 1
            if max_lenght < lenght:
                max_lenght = lenght
    width = 1.1 * max_lenght * len(xticks)  * fontsize/144
    bar_num = len(xticks) * legend_num
    min_bar_widht = 0.1
    total_bar_width = bar_num * min_bar_widht * 1.3
    if total_bar_width >=10:
        total_bar_width = 10
    if width < total_bar_width:
        width = total_bar_width
    return width

def plot_bar(plot_type,array,name_list_dict = None,legend = None,axis = None,ylabel = "Value",vmin = None,vmax = None,ncol = None,grid = None,tag = -1,save_path = None,show = False
        ,dpi = 300,bar_width = None,spasify_xticks = None,sup_fontsize = 10,title = ""
             ,height = None,width = None,log_y = False,sup_title = None,xlabel = None,legend_col = None,color_list = None,hline = None,marker = None):
    shape = array.shape


    if len(array[array!=meteva.base.IV]) ==0:
        print("所有的值都为缺失值")
        return

    if len(shape) ==1:
        if name_list_dict is None:
            name_list_dict = {}
            name_list_dict["x"] = np.arange(array.size).tolist()
            axis = "x"
        else:

            axis = list(name_list_dict.keys())[0]


        #xlabel = list(name_list_dict.keys())[0]
        #xticks = name_list_dict[xlabel]


        x_one = name_list_dict[axis][0]
        if isinstance(x_one,datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis],3)
        else:
            xticks_labels = []
            for local in name_list_dict[axis]:
                if isinstance(local,float):
                    xticks_labels.append(str(round(local, 6)))
                else:
                    xticks_labels.append(str(local))

        width_axis = meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize,legend_num= 1)

        width_wspace = sup_fontsize * 0.01
        width_one_subplot = width_axis +width_wspace

        spasify = 1
        if width is None:
            width = max(4,min(width_one_subplot,8))

        if width_one_subplot > width:
            spasify = int(math.ceil(width_axis / (width - width_wspace)))


        if spasify_xticks is not None:
            xticks_font = sup_fontsize * 1.0 * spasify_xticks * (width - width_wspace) / width_axis
            spasify = spasify_xticks
        else:
            xticks_font = sup_fontsize * 0.8

        x = np.arange(len(name_list_dict[axis]))
        if array.size + 1 == len(name_list_dict[axis]):
            x = x -0.5
            if isinstance (name_list_dict[axis][0],str) and name_list_dict[axis][0].find("<") ==0:
                x[0] += 0.5
            if isinstance (name_list_dict[axis][0],str) and (name_list_dict[axis][-1].find(">") == 0):
                x[-1] -= 0.5
        elif len(x) != len(name_list_dict[axis]):
            print("坐标的size和数据的size不匹配")
            return

        xticks = x[::spasify]
        if isinstance(x_one,datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis][::spasify],3)
        else:
            xticks_labels = xticks_labels[::spasify]



        if height is None:
            height = width / 2

        fig = plt.figure(figsize=(width, height), dpi=dpi)
        x = np.arange(array.size)
        y_plot = array[array != meteva.base.IV]
        x_plot = x[array!=meteva.base.IV]

        if log_y:
            array[array == 0] = meteva.base.IV
        if vmin is None:
            vmin1 = np.min(array[array != meteva.base.IV])
        else:
            vmin1 = vmin
        if vmax is None:
            vmax1 = np.max(array[array != meteva.base.IV])
        else:
            vmax1 = vmax

        dmax = vmax1 - vmin1
        if log_y and vmin1 <= 0:
            print("取对数坐标时数据的最小值不能<=0")

        if vmin is None:
            if log_y:
                pass
                vmin1 = vmin1 * (vmin1 / vmax1) ** 0.2
            else:
                if vmin1 < 0 or plot_type == "plot":
                    vmin1 = vmin1 - 0.1 * dmax
        if vmax is None:
            if log_y:
                vmax1 = vmax1 * (vmax1/vmin1)**0.3
            else:
                vmax1 = vmax1 + 0.2 * dmax

        if plot_type == "bar":
            if bar_width is None:
                width = 0.2
            else:
                width = bar_width

            if color_list is None:
                plt.bar(x_plot,y_plot,width= width *0.95)
            else:
                plt.bar(x_plot,y_plot,width= width *0.95,color = color_list[0])

            if len(array[array ==meteva.base.IV])>0:
                x_iv = x[array == meteva.base.IV]
                y_iv = np.zeros(x_iv.size)
                plt.plot(x_iv,y_iv,"^", color='k')
            if tag >= 0:
                # add data tag
                delta = (vmax1 - vmin1) / 20
                for a, b in zip(x_plot, y_plot):
                    fmt_tag = "%." + str(tag) + "f"
                    plt.text(a, b + delta, fmt_tag % b, ha="center", va="bottom", fontsize=sup_fontsize * 0.6)
        else:
            dat0 = array
            index_iv = np.where(dat0 == meteva.base.IV)
            if len(index_iv) == 0:
                if color_list is None:
                    plt.plot(x, dat0)
                else:
                    plt.plot(x, dat0,color = color_list[0])
            else:
                dat0_all = set_plot_IV_with_out_start_end(dat0)
                plt.plot(x, dat0_all, "--", linewidth=0.5, color="k")
                x_iv = x[index_iv[0]]
                dat0_iv = dat0_all[index_iv[0]]
                plt.plot(x_iv, dat0_iv, "x", color='k',markersize = 1)
                dat0_notiv = dat0.copy()
                dat0_notiv[dat0_notiv == meteva.base.IV] = np.nan
                if color_list is None:
                    plt.plot(x, dat0_notiv,marker = marker)
                else:
                    plt.plot(x, dat0_notiv,color = color_list[0],marker = marker)
            if tag >= 0:
                for ii in range(len(dat0)):
                    a = x[ii]
                    b = dat0[ii]
                    if np.isnan(b) or b == meteva.base.IV: continue
                    va = "center"
                    if ii > 0 and ii < len(dat0) - 1:
                        if b > dat0[ii - 1] and b > dat0[ii + 1]:
                            va = "bottom"
                        elif b < dat0[ii - 1] and b < dat0[ii + 1]:
                            va = "top"
                    fmt_tag = "%." + str(tag) + "f"
                    plt.text(a, b, fmt_tag % b, ha="center", va=va,
                             fontsize=sup_fontsize * 0.6)

        plt.xticks(xticks,xticks_labels,fontsize = xticks_font)
        plt.yticks(fontsize=sup_fontsize * 0.8)
        if xlabel is None:xlabel = axis
        plt.xlabel(xlabel,fontsize=sup_fontsize * 0.9)
        plt.ylabel(ylabel,fontsize = sup_fontsize * 0.9)

        if isinstance(title,list):
            title = title[0]
        plt.title(title,fontsize = sup_fontsize)
        plt.ylim(vmin1,vmax1)
        plt.xlim(-0.5, array.size - 0.5)
        if hline is not None:
            plt.axhline(hline,ls="--",c="k")
        if log_y:
            ax_one = plt.gca()
            for tick in ax_one.yaxis.get_major_ticks():
                tick.label1.set_fontproperties('stixgeneral')
            plt.yscale('log')
        if grid is not None:
            if grid:
                if plot_type == "bar":
                    plt.grid(axis="y")
                else:
                    plt.grid()
            else:
                pass
        else:
            if spasify > 2:
                if plot_type == "bar":
                    plt.grid(axis="y")
                else:
                    plt.grid()

    elif len(shape)==2:
        if name_list_dict is None:
            name_list_dict = {}
            list1 = np.arange(shape[0]).tolist()
            list2 = []
            for lv in list1:
                list2.append("y_" +str(lv))
            name_list_dict["y"] = list2
            name_list_dict["x"] = np.arange(shape[1]).tolist()
        keys  = list(name_list_dict.keys())
        dat = None
        if legend is None:
            if axis is None:
                legend = keys[0]
                axis = keys[1]
            else:
                if axis != keys[0]:
                    legend = keys[0]
                else:
                    legend = keys[1]
                    dat = array.T
        if legend == keys[1]:
            dat = array.T

        if dat is None:
            dat = array
        if legend not in keys:
            print("legend 参数的取值必须是name_list_dict的key")
        if axis not in keys:
            print("axis 参数的取值必须是name_list_dict的key")

        legend_list = name_list_dict[legend]
        legend_num = len(legend_list)
        x_one = name_list_dict[axis][0]

        if isinstance(x_one,datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis],3)
        else:
            xticks_labels = []
            for local in name_list_dict[axis]:
                if isinstance(local,float):
                    xticks_labels.append(str(round(local, 6)))
                else:
                    xticks_labels.append(str(local))

        width_axis = meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize,legend_num)
        width_axis_labels = meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize, 1)

        width_wspace =2
        width_one_subplot = width_axis + width_wspace
        if width_one_subplot < 2: width_one_subplot = 2
        if width is None:
            width = max(4,min(width_one_subplot,8))

        spasify = 1
        if width_one_subplot > width:
            spasify = int(math.ceil(width_axis_labels / (width - width_wspace)))
            #width_one_subplot = 10

        if spasify_xticks is not None:
            xticks_font = sup_fontsize * 1.0 * spasify_xticks * (width - width_wspace) / width_axis_labels
            spasify = spasify_xticks
        else:
            xticks_font = sup_fontsize * 0.8



        if height is None:
            height = width / 2

        if legend_col is None:
            legend_col = int(width * 8/ sup_fontsize)
            legend_row = int(math.ceil(legend_num/legend_col))
            legend_col = int(math.ceil(legend_num/legend_row))

        fig = plt.figure(figsize=(width, height), dpi=dpi)

        x = np.arange(0,len(name_list_dict[axis]),1)
        if dat.shape[1] + 1 == len(name_list_dict[axis]):
            x = x -0.5
            if isinstance (name_list_dict[axis][0],str) and name_list_dict[axis][0].find("<") ==0:
                x[0] += 0.5
            if isinstance (name_list_dict[axis][0],str) and (name_list_dict[axis][-1].find(">") == 0):
                x[-1] -= 0.5
        elif len(x) != len(name_list_dict[axis]):
            print("坐标的size和数据的size不匹配")
            return

        xticks = x[::spasify]
        if isinstance(x_one,datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis][::spasify],3)
        else:
            xticks_labels = xticks_labels[::spasify]

        if log_y:
            array[array == 0] = meteva.base.IV
        if vmin is None:
            vmin1 = np.min(array[array != meteva.base.IV])
        else:
            vmin1 = vmin
        if vmax is None:
            vmax1 = np.max(array[array != meteva.base.IV])
        else:
            vmax1 = vmax
        dmax = vmax1 - vmin1

        if log_y and vmin1 <= 0:
            print("取对数坐标时数据的最小值不能<=0")

        if vmin is None:
            if log_y:
                pass
                vmin1 = vmin1 * (vmin1 / vmax1) ** 0.2
            else:
                if vmin1 < 0 or plot_type == "plot":
                    vmin1 = vmin1 - 0.1 * dmax

        if vmax is None:
            if log_y:
                vmax1 = vmax1 * (vmax1/vmin1)**0.5
            else:
                vmax1 = vmax1 + 0.5 * dmax

        x = np.arange(dat.shape[1])
        if plot_type == "bar":
            if bar_width is None:
                bar_width = 0.7 / (legend_num + 2)
            legend0 = str(legend_list[0])
            if legend0.lower().find("ob")<0 and legend0.find("观测")<0 and legend0.find("实况")<0 and legend0.find("零场")<0:
                # 如果判断第一个legend不是观测想的，则跳过第一个自动颜色
                plt.bar(0,0)
            for i in range(legend_num):
                x1 = x + (i - legend_num/2 + 0.5) * bar_width
                dat0 = dat[i,:]
                y_plot = dat0[dat0 != meteva.base.IV]
                x_plot = x1[dat0 != meteva.base.IV]
                if color_list is None:
                    if meteva.base.plot_color_dict is not None and legend_list[i] in meteva.base.plot_color_dict.keys():
                        color_set1 = meteva.base.plot_color_dict[legend_list[i]]
                        plt.bar(x_plot, y_plot, width=bar_width * 0.95, label=legend_list[i],color = color_set1)
                    else:
                        plt.bar(x_plot, y_plot,width=bar_width * 0.95,label = legend_list[i])
                else:
                    plt.bar(x_plot, y_plot, width=bar_width * 0.95, label=legend_list[i],color = color_list[i])

                if len(dat0[dat0 == meteva.base.IV]) > 0:
                    x_iv = x1[dat0 == meteva.base.IV]
                    y_iv = np.zeros(x_iv.size)
                    plt.plot(x_iv, y_iv, "^", color='k')
                if tag >= 0:
                    # add data tag
                    delta = (vmax1 - vmin1) / 20
                    for a, b in zip(x_plot, y_plot):
                        fmt_tag = "%." + str(tag) + "f"
                        plt.text(a, b + delta, fmt_tag % b, ha="center", va="bottom", fontsize=sup_fontsize * 0.6)
        else:
            legend0 = str(legend_list[0])
            if legend0.lower().find("ob")<0 and legend0.find("观测")<0 and legend0.find("实况")<0 and legend0.find("零场")<0:
                # 如果判断第一个legend不是观测想的，则跳过第一个自动颜色
                plt.plot(0,0)
            for i in range(legend_num):
                dat0 = dat[i, :]
                index_iv = np.where(dat0 == meteva.base.IV)
                if len(index_iv) == 0:
                    if color_list is None:
                        if meteva.base.plot_color_dict is not None and legend_list[i] in meteva.base.plot_color_dict.keys():
                            color_set1 = meteva.base.plot_color_dict[legend_list[i]]
                            plt.plot(x, dat0, label=legend_list[i],color=color_set1)
                        else:
                            plt.plot(x, dat0, label=legend_list[i])
                    else:
                        plt.plot(x, dat0, label=legend_list[i],color = color_list[i])
                else:
                    dat0_all = set_plot_IV_with_out_start_end(dat0)
                    plt.plot(x, dat0_all, "--", linewidth=0.5, color="k")
                    x_iv = x[index_iv[0]]
                    dat0_iv = dat0_all[index_iv[0]]
                    plt.plot(x_iv, dat0_iv, "x", color='k',markersize = 1)
                    dat0_notiv = dat0.copy()
                    dat0_notiv[dat0_notiv == meteva.base.IV] = np.nan
                    if color_list is None:
                        if meteva.base.plot_color_dict is not None and legend_list[i] in meteva.base.plot_color_dict.keys():
                            color_set1 = meteva.base.plot_color_dict[legend_list[i]]
                            plt.plot(x, dat0_notiv, label=name_list_dict[legend][i],color = color_set1,marker = marker)
                        else:
                            plt.plot(x, dat0_notiv, label=name_list_dict[legend][i],marker = marker)
                    else:
                        plt.plot(x, dat0_notiv, label=name_list_dict[legend][i],color = color_list[i],marker = marker)
                if tag >= 0:
                    for ii in range(len(dat0)):
                        a = x[ii]
                        b = dat0[ii]
                        if np.isnan(b) or b == meteva.base.IV: continue
                        va = "center"
                        if ii > 0 and ii < len(dat0) - 1:
                            if b > dat0[ii - 1] and b > dat0[ii + 1]:
                                va = "bottom"
                            elif b < dat0[ii - 1] and b < dat0[ii + 1]:
                                va = "top"
                        fmt_tag = "%." + str(tag) + "f"
                        plt.text(a, b, fmt_tag % b, ha="center", va=va,
                                 fontsize=sup_fontsize * 0.6)

        plt.legend(fontsize =sup_fontsize * 0.8,ncol = legend_col,loc = "upper center")
        plt.xticks(xticks, xticks_labels, fontsize=xticks_font)
        plt.yticks(fontsize=sup_fontsize * 0.8)
        if xlabel is None:xlabel = axis
        plt.xlabel(xlabel, fontsize=sup_fontsize * 0.9)
        plt.ylabel(ylabel, fontsize=sup_fontsize * 0.9)
        if isinstance(title,list):
            title = title[0]
        plt.title(title, fontsize=sup_fontsize)
        plt.xlim(-0.5, dat.shape[1] - 0.5)
        plt.ylim(vmin1,vmax1)
        if hline is not None:
            plt.axhline(hline,ls="--",c="k")
        if log_y:
            ax_one = plt.gca()
            for tick in ax_one.yaxis.get_major_ticks():
                tick.label1.set_fontproperties('stixgeneral')
            plt.yscale('log')
        if grid is not None:
            if grid:
                if plot_type == "bar":
                    plt.grid(axis="y")
                else:
                    plt.grid()
            else:
                pass
        else:
            if spasify > 2:
                if plot_type == "bar":
                    plt.grid(axis="y")
                else:
                    plt.grid()

    elif len(shape)==3:
        if name_list_dict is None:
            name_list_dict = {}
            name_list_dict["z"] = np.arange(shape[0])
            list1 = np.arange(shape[1]).tolist()
            list2 = []
            for lv in list1:
                list2.append("y_" +str(lv))
            name_list_dict["y"] = list2
            name_list_dict["x"] = np.arange(shape[2])
            legend = "y"
            axis = "x"
            subplot = "z"
        keys = list(name_list_dict.keys())
        if legend is None:
            if axis is None:
                legend = keys[1]
                axis = keys[2]
                subplot = keys[0]
            else:
                if axis == keys[2]:
                    legend = keys[1]
                    subplot = keys[0]
                elif axis == keys[1]:
                    legend = keys[2]
                    subplot = keys[0]
                else:
                    legend = keys[2]
                    subplot = keys[1]
        else:
            if axis is None:
                if legend == keys[0]:
                    axis = keys[2]
                    subplot = keys[1]
                elif legend == keys[1]:
                    axis = keys[2]
                    subplot = keys[0]
                else:
                    axis = keys[1]
                    subplot = keys[0]
            else:
                indexlist = [0,1,2]
                indexlist.remove(keys.index(legend))
                indexlist.remove(keys.index(axis))
                subplot = keys[indexlist[0]]
        if legend not in keys:
            print("legend 参数的取值必须是name_list_dict的key")
        if axis not in keys:
            print("axis 参数的取值必须是name_list_dict的key")
        newshape = (keys.index(subplot),keys.index(legend),keys.index(axis))
        data = array.transpose(newshape)
        legend_num = len(name_list_dict[legend])

        x_one = name_list_dict[axis][0]
        if isinstance(x_one,datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis],3)
        elif axis.find("dayofyear")>=0:
            xticks_labels = meteva.product.get_dayofyear_str_list(name_list_dict[axis])
        else:
            xticks_labels = []
            for local in name_list_dict[axis]:
                if isinstance(local,float):
                    xticks_labels.append(str(round(local, 6)))
                else:
                    xticks_labels.append(str(local))

        width_axis = meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize,legend_num)
        width_axis_labels =  meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize,1)

        width_wspace = sup_fontsize * 0.1
        width_one_subplot = width_axis +width_wspace
        if width_one_subplot <2:width_one_subplot = 2
        subplot_num = len(name_list_dict[subplot])
        spasify = 1


        if ncol is not None:
            if width_one_subplot >8/ncol:
                spasify = int(math.ceil(width_axis_labels/(8/ncol - width_wspace)))
                width_one_subplot = 8/ncol
        else:
            if width_one_subplot >8:
                spasify = int(math.ceil(width_axis_labels/(8 - width_wspace)))
                width_one_subplot = 8


        if spasify_xticks is not None:
            xticks_font = sup_fontsize * 1.0 * spasify_xticks * (width_one_subplot - width_wspace) / width_axis_labels
            spasify = spasify_xticks
        else:
            xticks_font = sup_fontsize * 0.8

        x = np.arange(len(name_list_dict[axis]))
        if data.shape[2] + 1 == len(name_list_dict[axis]):
            x = x -0.5
            if isinstance (name_list_dict[axis][0],str) and name_list_dict[axis][0].find("<") ==0:
                x[0] += 0.5
            if isinstance (name_list_dict[axis][0],str) and (name_list_dict[axis][-1].find(">") == 0):
                x[-1] -= 0.5
        elif len(x) != len(name_list_dict[axis]):
            print("坐标的size和数据的size不匹配")
            return


        xticks = x[::spasify]

        if isinstance(x_one,datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis][::spasify],3)
        elif axis.find("dayofyear")>=0:
            xticks_labels = meteva.product.get_dayofyear_str_list(name_list_dict[axis][::spasify])
        else:
            xticks_labels = xticks_labels[::spasify]

        xticks_labels_None = []
        for i in range(len(xticks_labels)):
            xticks_labels_None.append("")


        if ncol is None:
            ncol = int(8/width_one_subplot)
            nrow = int(math.ceil(subplot_num/ncol))
            ncol = int(math.ceil(subplot_num/nrow))
        else:
            nrow = int(math.ceil(len(name_list_dict[subplot])/ncol))

        if width is None:
            width_fig = width_one_subplot * ncol
            if width_fig > 8: width_fig = 8
            if width_fig < 4: width_fig = 4
        else:
            width_fig = width

        height_axis = width_axis * 0.5
        height_hspace = sup_fontsize * 0.01
        height_suplegend = 1
        if height is None:
            height_fig = nrow * (height_axis+height_hspace) + height_suplegend
            if height_fig > 6: height_fig = 6
            if height_fig < 3: height_fig = 3
        else:
            height_fig = height



        fig = plt.figure(figsize=(width_fig, height_fig), dpi=dpi)
        x = np.arange(data.shape[2])
        hspace = height_hspace/(width_axis*0.5)
        wspace = width_wspace/width_one_subplot

        plt.subplots_adjust(left=0, bottom=0.0, right=1.0, top = 1 - height_suplegend/height_fig,
                            hspace=0.08,wspace=wspace)

        if bar_width is None:
            width = 0.7 / (legend_num + 2)
        else:
            width = bar_width
        ax_top = None
        for k in range(subplot_num):
            #print(data.shape)
            data_k = data[k,:,:]
            if log_y:
                data_k[data_k == 0] = meteva.base.IV
            if vmin is None:
                dat_k0 = data_k[data_k != meteva.base.IV]
                if dat_k0.size>0:
                    vmin1 = np.min(dat_k0)
                else:
                    vmin1 = 0
            else:
                if isinstance(vmin, list):
                    if len(vmin) != subplot_num:
                        print("vmin 参数的个数和 子图个数不一致，请重新设置")
                        return
                    else:
                        vmin1 = vmin[k]
                else:
                    vmin1 = vmin

            if vmax is None:
                dat_k0 = data_k[data_k != meteva.base.IV]
                if dat_k0.size>0:
                    vmax1 = np.max(dat_k0)
                else:
                    vmax1 = vmin1 + 0.1
            else:
                if isinstance(vmax, list):
                    if len(vmax) != subplot_num:
                        print("vmin 参数的个数和 子图个数不一致，请重新设置")
                        return
                    else:
                        vmax1 = vmax[k]
                else:
                    vmax1 = vmax

            dmax = vmax1- vmin1


            if log_y and vmin1 <0:
                print("取对数坐标时数据的最小值不能<0")
            if vmin is None:
                if log_y:
                    pass
                    vmin1 = vmin1 * (vmin1/vmax1) ** 0.2
                else:
                    if vmin1 < 0 or plot_type == "plot":
                        vmin1 = vmin1 - 0.1 * dmax
            if vmax is None:
                if log_y:
                    vmax1 = vmax1 * (vmax1 / vmin1) ** 0.5
                else:
                    vmax1 = vmax1 + 0.5 * dmax


            ax_one = plt.subplot(nrow, ncol, k + 1)
            if k==0:ax_top = ax_one
            legend0 = str(name_list_dict[legend][0])
            if legend0.lower().find("ob")<0 and legend0.find("观测")<0 and legend0.find("实况")<0 and legend0.find("零场")<0:
                plt.bar(0,0)
                plt.plot(0,0)
            for i in range(legend_num):
                if plot_type == "bar":
                    x1 = x + (i - legend_num / 2 + 0.5) * width
                    dat0 = data[k,i,:]
                    y_plot = dat0[dat0 != meteva.base.IV]
                    x_plot = x1[dat0 != meteva.base.IV]
                    if color_list is None:
                        if meteva.base.plot_color_dict is not None and name_list_dict[legend][i] in meteva.base.plot_color_dict.keys():
                            color_set1 = meteva.base.plot_color_dict[name_list_dict[legend][i]]
                            if k == 0:
                                plt.bar(x_plot, y_plot, width=width * 0.95, label=name_list_dict[legend][i],color = color_set1)
                            else:
                                plt.bar(x_plot, y_plot, width=width * 0.95,color = color_set1)
                        else:
                            if k ==0:
                                plt.bar(x_plot, y_plot, width=width * 0.95, label=name_list_dict[legend][i])
                            else:
                                plt.bar(x_plot, y_plot, width=width * 0.95)
                    else:
                        if k ==0:
                            plt.bar(x_plot, y_plot, width=width * 0.95, label=name_list_dict[legend][i],color = color_list[i])
                        else:
                            plt.bar(x_plot, y_plot, width=width * 0.95,color = color_list[i])
                    if tag >=0:
                        # add data tag
                        delta = (vmax1- vmin1)/20
                        for a,b in zip(x_plot,y_plot):
                            fmt_tag = "%." + str(tag)+"f"
                            plt.text(a,b + delta,fmt_tag % b,ha = "center",va = "bottom",fontsize = sup_fontsize *0.6)

                    if len(dat0[dat0 == meteva.base.IV]) > 0:
                        x_iv = x1[dat0 == meteva.base.IV]
                        y_iv = np.zeros(x_iv.size)
                        plt.plot(x_iv, y_iv, "^", color='k')

                else:
                    dat0 = data[k, i, :]
                    index_iv = np.where(dat0 == meteva.base.IV)
                    if len(index_iv[0]) == 0:
                        if color_list is None:
                            if meteva.base.plot_color_dict is not None and name_list_dict[legend][i] in meteva.base.plot_color_dict.keys():
                                color_set1 = meteva.base.plot_color_dict[name_list_dict[legend][i]]
                                if k == 0:
                                    plt.plot(x, data[k, i, :], label=name_list_dict[legend][i],color = color_set1,marker = marker)
                                else:
                                    plt.plot(x, data[k, i, :],color = color_set1,marker = marker)
                            else:
                                if k == 0:
                                    plt.plot(x, data[k, i, :], label=name_list_dict[legend][i],marker = marker)
                                else:
                                    plt.plot(x, data[k, i, :],marker = marker)
                        else:
                            if k == 0:
                                plt.plot(x, data[k, i, :], label=name_list_dict[legend][i],color = color_list[i],marker = marker)
                            else:
                                plt.plot(x, data[k, i, :],color = color_list[i],marker = marker)
                    else:
                        dat0_all = set_plot_IV_with_out_start_end(dat0)
                        plt.plot(x, dat0_all, "--", linewidth=0.5, color="k")
                        x_iv = x[index_iv[0]]
                        dat0_iv = dat0_all[index_iv[0]]
                        plt.plot(x_iv, dat0_iv, "x", color='k',markersize = 1)
                        dat0_notiv = dat0.copy()
                        dat0_notiv[dat0_notiv == meteva.base.IV] = np.nan
                        if color_list is None:
                            if meteva.base.plot_color_dict is not None and name_list_dict[legend][i] in meteva.base.plot_color_dict.keys():
                                color_set1 = meteva.base.plot_color_dict[name_list_dict[legend][i]]
                                if k == 0:
                                    plt.plot(x, dat0_notiv, label=name_list_dict[legend][i], color=color_set1,marker = marker)
                                else:
                                    plt.plot(x, dat0_notiv, color=color_set1,marker = marker)
                            else:
                                if k == 0:
                                    plt.plot(x, dat0_notiv, label=name_list_dict[legend][i],marker = marker)
                                else:
                                    plt.plot(x, dat0_notiv,marker = marker)
                        else:
                            if k == 0:
                                plt.plot(x, dat0_notiv, label=name_list_dict[legend][i],color = color_list[i],marker = marker)
                            else:
                                plt.plot(x, dat0_notiv,color = color_list[i],marker = marker)

                    if tag >= 0:
                        for ii in range(len(dat0)):
                            a = x[ii]
                            b = dat0[ii]
                            if np.isnan(b) or b == meteva.base.IV:continue
                            va = "center"
                            if ii>0 and ii < len(dat0) -1:
                                if b > dat0[ii-1] and b > dat0[ii+1]:
                                    va = "bottom"
                                elif b < dat0[ii-1] and b < dat0[ii+1]:
                                    va = "top"
                            fmt_tag = "%." + str(tag) + "f"
                            plt.text(a, b , fmt_tag % b, ha="center", va=va,
                                     fontsize=sup_fontsize * 0.6)


            ki = k % ncol
            kj = int(k / ncol)
            knext_row = ki + (kj+1) * ncol
            #print(knext_row)
            #print(subplot_num)
            if xlabel is None: xlabel = axis
            if knext_row>=subplot_num:
                #plt.xticks(x[::spasify], name_list_dict[axis][::spasify], fontsize=sup_fontsize * 0.8)
                plt.xticks(xticks, xticks_labels, fontsize=xticks_font)
                plt.xlabel(xlabel, fontsize=sup_fontsize * 0.9)
            else:
                plt.xticks(xticks,xticks_labels_None)
            xminorLocator = mpl.ticker.MultipleLocator(1)  # 将x轴次刻度标签设置xmi
            ax_one.xaxis.set_minor_locator(xminorLocator)
            plt.yticks(fontsize=sup_fontsize * 0.8)

            plt.ylabel(ylabel, fontsize=sup_fontsize * 0.9)
            if hline is not None:
                plt.axhline(hline, ls="--", c="k")
            if isinstance(title, list):
                if(len(title) != subplot_num):
                    print("子图数和设置的子图标题数不一致")
                    return
                title1 = title[k]
            else:
                if subplot_num>1:
                    title1 = title +  str(name_list_dict[subplot][k])
                else:
                    title1 = title
            if subplot_num >1:
                y1 =  1 - 0.035 *  sup_fontsize / (height_fig/nrow)
                plt.title(title1, fontsize=sup_fontsize,y = y1)
            else:
                plt.title(title1, fontsize=sup_fontsize)

            plt.xlim(-0.5, data.shape[2] - 0.5)

            if log_y:
                for tick in ax_one.yaxis.get_major_ticks():
                    tick.label1.set_fontproperties('stixgeneral')
                plt.yscale('log')

            plt.ylim(vmin1,vmax1)
            if grid is not None:
                if grid:
                    if plot_type == "bar":
                        plt.grid(axis = "y")
                    else:
                        plt.grid()
                else:
                    pass
            else:
                if spasify >2:
                    if plot_type == "bar":
                        plt.grid(axis="y")
                    else:
                        plt.grid()

        #print("a")
        if sup_title is not None:


            if legend_num ==1:
                strss = sup_title.split("\n")
                by = 1 - (height_suplegend - len(strss) * sup_fontsize * 0.01) / height_fig + 0.025
                plt.suptitle(sup_title, y = by,fontsize=sup_fontsize )
            else:
                width_suptitle = caculate_str_width(sup_title,sup_fontsize)
                if legend_col is None:
                    legend_col = int((width_fig - width_suptitle) *12 / sup_fontsize)
                    if legend_col <1:legend_col = 1
                    legend_row = int(math.ceil(legend_num / legend_col))
                    legend_col = int(math.ceil(legend_num / legend_row))
                else:
                    legend_row = int(math.ceil(legend_num / legend_col))
                strss = sup_title.split("\n")
                #by = 1 - (height_suplegend - len(strss) * sup_fontsize * 0.01) / height_fig + 0.025

                by = ax_top.bbox.ymax / fig.bbox.ymax + (len(strss) * sup_fontsize * 0.015 + 0.1) / height_fig
                plt.suptitle(sup_title, x = 0,y = by, fontsize=sup_fontsize ,horizontalalignment='left')

                #by = 1 - (height_suplegend - legend_row * sup_fontsize * 0.9 * 0.02) / height_fig + 0.05
                by = ax_top.bbox.ymax / fig.bbox.ymax + (legend_row * sup_fontsize * 0.7 * 0.02 + 0.15) / height_fig
                if subplot_num >1:
                    fig.legend(fontsize = sup_fontsize *0.7,ncol = legend_col,loc = "upper right",
                           bbox_to_anchor=(1,by))
                else:
                    plt.legend(fontsize = sup_fontsize *0.7,ncol = legend_col,loc = "upper right")
        else:
            if legend_num > 1:
                if legend_col is None:
                    legend_col = int(width_fig * 8 / sup_fontsize)
                    if legend_col < 1: legend_col = 1
                    legend_row = int(math.ceil(legend_num / legend_col))
                    legend_col = int(math.ceil(legend_num / legend_row))
                else:
                    legend_row = int(math.ceil(legend_num / legend_col))
                #print(height_fig)
                by = ax_top.bbox.ymax/fig.bbox.ymax + (legend_row * sup_fontsize * 0.9 * 0.03 + 0.1) / height_fig

                #by = 1 - (height_suplegend - legend_row * sup_fontsize * 0.9 * 0.03) / height_fig + 0.025
                #print(by)

                if subplot_num > 1:
                    fig.legend(fontsize=sup_fontsize * 0.8, ncol=legend_col, loc="upper center",
                               bbox_to_anchor=(0.52, by))
                else:
                    plt.legend(fontsize=sup_fontsize * 0.8, ncol=legend_col, loc="upper center")

    else:
        print("array不能超过3维")
        return
        xticks = []
        for index in index_list:
            if not type(index) == str:
                index = str(index)
            xticks.append(index)
    if save_path is None:
        show = True
    else:
        meteva.base.creat_path(save_path)
        plt.savefig(save_path,bbox_inches='tight')
        print("检验结果已以图片形式保存至" + save_path)
    if show:
        plt.show()
    plt.close()



def bar_line(array,type_list,name_list_dict = None,legend = None,axis = None,vmin_bar = None,vmax_bar = None,
            vmin_line = None,vmax_line = None ,ncol = None,grid = None,tag = -1,save_path = None,show = False
        ,dpi = 300,bar_width = None,spasify_xticks = None,sup_fontsize = 10,title = ""
             ,height = None,width = None,log_y_bar = False,log_y_line = False,sup_title = None,
             xlabel = None,ylabel_bar = "Value",ylabel_line = "Value",legend_col = None,color_list = None,hline = None):
    shape = array.shape


    if len(array[array!=meteva.base.IV]) ==0:
        print("所有的值都为缺失值")
        return

    if len(shape)==2:
        if name_list_dict is None:
            name_list_dict = {}
            list1 = np.arange(shape[0]).tolist()
            list2 = []
            for lv in list1:
                list2.append("y_" +str(lv))
            name_list_dict["y"] = list2
            name_list_dict["x"] = np.arange(shape[1]).tolist()
        keys  = list(name_list_dict.keys())
        dat = None
        if legend is None:
            if axis is None:
                legend = keys[0]
                axis = keys[1]
            else:
                if axis != keys[0]:
                    legend = keys[0]
                else:
                    legend = keys[1]
                    dat = array.T
        if legend == keys[1]:
            dat = array.T

        if dat is None:
            dat = array
        if legend not in keys:
            print("legend 参数的取值必须是name_list_dict的key")
        if axis not in keys:
            print("axis 参数的取值必须是name_list_dict的key")

        legend_list = name_list_dict[legend]
        legend_num = len(legend_list)
        x_one = name_list_dict[axis][0]

        if isinstance(x_one,datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis],3)
        else:
            xticks_labels = []
            for local in name_list_dict[axis]:
                if isinstance(local,float):
                    xticks_labels.append(str(round(local, 6)))
                else:
                    xticks_labels.append(str(local))

        width_axis = meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize,legend_num)
        width_axis_labels = meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize, 1)

        width_wspace =2
        width_one_subplot = width_axis + width_wspace
        if width_one_subplot < 2: width_one_subplot = 2
        if width is None:
            width = max(4,min(width_one_subplot,8))

        spasify = 1
        if width_one_subplot > width:
            spasify = int(math.ceil(width_axis_labels / (width - width_wspace)))
            #width_one_subplot = 10

        if spasify_xticks is not None:
            xticks_font = sup_fontsize * 1.0 * spasify_xticks * (width - width_wspace) / width_axis_labels
            spasify = spasify_xticks
        else:
            xticks_font = sup_fontsize * 0.8



        if height is None:
            height = width / 2

        if legend_col is None:
            legend_col = int(width * 8/ sup_fontsize)
            legend_row = int(math.ceil(legend_num/legend_col))
            legend_col = int(math.ceil(legend_num/legend_row))

        fig = plt.figure(figsize=(width, height), dpi=dpi)
        ax1 = fig.add_subplot(111)

        x = np.arange(0,len(name_list_dict[axis]),1)
        if dat.shape[1] + 1 == len(name_list_dict[axis]):
            x = x -0.5
            if isinstance (name_list_dict[axis][0],str) and name_list_dict[axis][0].find("<") ==0:
                x[0] += 0.5
            if isinstance (name_list_dict[axis][0],str) and (name_list_dict[axis][-1].find(">") == 0):
                x[-1] -= 0.5
        elif len(x) != len(name_list_dict[axis]):
            print("坐标的size和数据的size不匹配")
            return

        xticks = x[::spasify]
        if isinstance(x_one,datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis][::spasify],3)
        else:
            xticks_labels = xticks_labels[::spasify]


        dat_bar_list = []
        dat_line_list = []
        for i in range(legend_num):
            if type_list[i] == "bar":
                if log_y_bar:
                    dat[i,dat[i,:]==0] = meteva.base.IV
                dat_bar_list.append(dat[i,:])
            else:
                if log_y_line:
                    dat[i,dat[i,:]==0] = meteva.base.IV
                dat_line_list.append(dat[i,:])

        dat_bar = np.array(dat_bar_list)
        dat_line = np.array(dat_line_list)

        if vmin_bar is None:
            vmin1_bar = np.min(dat_bar[dat_bar != meteva.base.IV])
        else:
            vmin1_bar = vmin_bar
        if vmax_bar is None:
            vmax1_bar = np.max(dat_bar[dat_bar != meteva.base.IV])
        else:
            vmax1_bar = vmax_bar
        dmax_bar = vmax1_bar - vmin1_bar

        if log_y_bar and vmin1_bar <= 0:
            print("取对数坐标时数据的最小值不能<=0")

        if vmin_bar is None:
            if log_y_bar:
                pass
                vmin1_bar = vmin1_bar * (vmin1_bar / vmax1_bar) ** 0.2
            else:
                if vmin1_bar < 0:
                    vmin1_bar = vmin1_bar - 0.1 * dmax_bar

        if vmax_bar is None:
            if log_y_bar:
                vmax1_bar = vmax1_bar * (vmax1_bar/vmin1_bar)**0.5
            else:
                vmax1_bar = vmax1_bar + 0.5 * dmax_bar



        if vmin_line is None:
            vmin1_line = np.min(dat_line[dat_line != meteva.base.IV])
        else:
            vmin1_line = vmin_line
        if vmax_line is None:
            vmax1_line = np.max(dat_line[dat_line != meteva.base.IV])
        else:
            vmax1_line = vmax_line
        dmax_line = vmax1_line - vmin1_line

        if log_y_line and vmin1_line <= 0:
            print("取对数坐标时数据的最小值不能<=0")

        if vmin_line is None:
            if log_y_line:
                pass
                vmin1_line = vmin1_line * (vmin1_line / vmax1_line) ** 0.2
            else:
                vmin1_line = vmin1_line - 0.1 * dmax_line

        if vmax_line is None:
            if log_y_line:
                vmax1_line = vmax1_line * (vmax1_line/vmin1_line)**0.5
            else:
                vmax1_line = vmax1_line + 0.5 * dmax_line

        x = np.arange(dat.shape[1])

        if bar_width is None:
            bar_width = 0.7 / (legend_num + 2)
        legend0 = str(legend_list[0])
        if legend0.lower().find("ob")<0 and legend0.find("观测")<0 and legend0.find("实况")<0 and legend0.find("零场")<0:
            # 如果判断第一个legend不是观测想的，则跳过第一个自动颜色
            plt.bar(0,0)

        for i in range(legend_num):
            if type_list[i] =="bar":
                x1 = x + (i - legend_num/2 + 0.5) * bar_width
                dat0 = dat[i,:]
                y_plot = dat0[dat0 != meteva.base.IV]
                x_plot = x1[dat0 != meteva.base.IV]
                if color_list is None:
                    if meteva.base.plot_color_dict is not None and legend_list[i] in meteva.base.plot_color_dict.keys():
                        color_set1 = meteva.base.plot_color_dict[legend_list[i]]
                        plt.bar(x_plot, y_plot, width=bar_width * 0.95, label=legend_list[i],color = color_set1)
                    else:
                        plt.bar(x_plot, y_plot,width=bar_width * 0.95,label = legend_list[i])
                else:
                    plt.bar(x_plot, y_plot, width=bar_width * 0.95, label=legend_list[i],color = color_list[i])

                if len(dat0[dat0 == meteva.base.IV]) > 0:
                    x_iv = x1[dat0 == meteva.base.IV]
                    y_iv = np.zeros(x_iv.size)
                    plt.plot(x_iv, y_iv, "^", color='k')
                if tag >= 0:
                    # add data tag
                    delta = (vmax1_bar - vmin1_bar) / 20
                    for a, b in zip(x_plot, y_plot):
                        fmt_tag = "%." + str(tag) + "f"
                        plt.text(a, b + delta, fmt_tag % b, ha="center", va="bottom", fontsize=sup_fontsize * 0.6)

        plt.yticks(fontsize=sup_fontsize * 0.8)
        plt.ylabel(ylabel_bar, fontsize=sup_fontsize * 0.9)
        if isinstance(title, list):
            title = title[0]
        plt.ylim(vmin1_bar, vmax1_bar)

        if log_y_bar:
            ax_one = plt.gca()
            for tick in ax_one.yaxis.get_major_ticks():
                tick.label1.set_fontproperties('stixgeneral')
            plt.yscale('log')
        plt.legend(fontsize =sup_fontsize * 0.8,ncol = legend_col,loc = "upper left")

        ax2 = ax1.twinx()

        for i in range(legend_num):
            if type_list[i] != "bar":
                dat0 = dat[i, :]
                index_iv = np.where(dat0 == meteva.base.IV)
                if len(index_iv) == 0:
                    if color_list is None:
                        if meteva.base.plot_color_dict is not None and legend_list[i] in meteva.base.plot_color_dict.keys():
                            color_set1 = meteva.base.plot_color_dict[legend_list[i]]
                            plt.plot(x, dat0, label=legend_list[i],color=color_set1)
                        else:
                            plt.plot(x, dat0, label=legend_list[i])
                    else:
                        plt.plot(x, dat0, label=legend_list[i],color = color_list[i])
                else:
                    dat0_all = set_plot_IV_with_out_start_end(dat0)
                    plt.plot(x, dat0_all, "--", linewidth=0.5, color="k")
                    x_iv = x[index_iv[0]]
                    dat0_iv = dat0_all[index_iv[0]]
                    plt.plot(x_iv, dat0_iv, "x", color='k',markersize = 1)
                    dat0_notiv = dat0.copy()
                    dat0_notiv[dat0_notiv == meteva.base.IV] = np.nan
                    if color_list is None:
                        if meteva.base.plot_color_dict is not None and legend_list[i] in meteva.base.plot_color_dict.keys():
                            color_set1 = meteva.base.plot_color_dict[legend_list[i]]
                            plt.plot(x, dat0_notiv, label=name_list_dict[legend][i],color = color_set1)
                        else:
                            plt.plot(x, dat0_notiv, label=name_list_dict[legend][i])
                    else:
                        plt.plot(x, dat0_notiv, label=name_list_dict[legend][i],color = color_list[i])
                if tag >= 0:
                    for ii in range(len(dat0)):
                        a = x[ii]
                        b = dat0[ii]
                        if np.isnan(b) or b == meteva.base.IV: continue
                        va = "center"
                        if ii > 0 and ii < len(dat0) - 1:
                            if b > dat0[ii - 1] and b > dat0[ii + 1]:
                                va = "bottom"
                            elif b < dat0[ii - 1] and b < dat0[ii + 1]:
                                va = "top"
                        fmt_tag = "%." + str(tag) + "f"
                        plt.text(a, b, fmt_tag % b, ha="center", va=va,
                                 fontsize=sup_fontsize * 0.6)

        plt.legend(fontsize =sup_fontsize * 0.8,ncol = legend_col,loc = "upper right")

        plt.xticks(xticks, xticks_labels, fontsize=xticks_font)
        plt.yticks(fontsize=sup_fontsize * 0.8)
        if xlabel is None:xlabel = axis
        plt.xlabel(xlabel, fontsize=sup_fontsize * 0.9)
        plt.ylabel(ylabel_line, fontsize=sup_fontsize * 0.9)
        if isinstance(title,list):
            title = title[0]
        plt.title(title, fontsize=sup_fontsize)
        plt.xlim(-0.5, dat.shape[1] - 0.5)
        plt.ylim(vmin1_line,vmax1_line)
        if hline is not None:
            plt.axhline(hline, ls="--", c="k")
        if log_y_line:
            ax_one = plt.gca()
            for tick in ax_one.yaxis.get_major_ticks():
                tick.label1.set_fontproperties('stixgeneral')
            plt.yscale('log')

        if grid is not None:
            if grid:
                plt.grid(axis="y")

            else:
                pass


    elif len(shape)==3:
        if name_list_dict is None:
            name_list_dict = {}
            name_list_dict["z"] = np.arange(shape[0])
            list1 = np.arange(shape[1]).tolist()
            list2 = []
            for lv in list1:
                list2.append("y_" + str(lv))
            name_list_dict["y"] = list2
            name_list_dict["x"] = np.arange(shape[2])
            legend = "y"
            axis = "x"
            subplot = "z"
        keys = list(name_list_dict.keys())
        if legend is None:
            if axis is None:
                legend = keys[1]
                axis = keys[2]
                subplot = keys[0]
            else:
                if axis == keys[2]:
                    legend = keys[1]
                    subplot = keys[0]
                elif axis == keys[1]:
                    legend = keys[2]
                    subplot = keys[0]
                else:
                    legend = keys[2]
                    subplot = keys[1]
        else:
            if axis is None:
                if legend == keys[0]:
                    axis = keys[2]
                    subplot = keys[1]
                elif legend == keys[1]:
                    axis = keys[2]
                    subplot = keys[0]
                else:
                    axis = keys[1]
                    subplot = keys[0]
            else:
                indexlist = [0, 1, 2]
                indexlist.remove(keys.index(legend))
                indexlist.remove(keys.index(axis))
                subplot = keys[indexlist[0]]
        if legend not in keys:
            print("legend 参数的取值必须是name_list_dict的key")
        if axis not in keys:
            print("axis 参数的取值必须是name_list_dict的key")
        newshape = (keys.index(subplot), keys.index(legend), keys.index(axis))
        data = array.transpose(newshape)
        legend_num = len(name_list_dict[legend])

        x_one = name_list_dict[axis][0]
        if isinstance(x_one, datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis], 3)
        elif axis.find("dayofyear") >= 0:
            xticks_labels = meteva.product.get_dayofyear_str_list(name_list_dict[axis])
        else:
            xticks_labels = []
            for local in name_list_dict[axis]:
                if isinstance(local, float):
                    xticks_labels.append(str(round(local, 6)))
                else:
                    xticks_labels.append(str(local))

        width_axis = meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize, legend_num)
        width_axis_labels = meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize, 1)

        width_wspace = sup_fontsize * 0.1
        width_one_subplot = width_axis + width_wspace
        if width_one_subplot < 2: width_one_subplot = 2
        subplot_num = len(name_list_dict[subplot])
        spasify = 1

        if ncol is not None:
            if width_one_subplot > 8 / ncol:
                spasify = int(math.ceil(width_axis_labels / (8 / ncol - width_wspace)))
                width_one_subplot = 8 / ncol
        else:
            if width_one_subplot > 8:
                spasify = int(math.ceil(width_axis_labels / (8 - width_wspace)))
                width_one_subplot = 8

        if spasify_xticks is not None:
            xticks_font = sup_fontsize * 1.0 * spasify_xticks * (width_one_subplot - width_wspace) / width_axis_labels
            spasify = spasify_xticks
        else:
            xticks_font = sup_fontsize * 0.8

        x = np.arange(len(name_list_dict[axis]))
        if data.shape[2] + 1 == len(name_list_dict[axis]):
            x = x - 0.5
            if isinstance(name_list_dict[axis][0], str) and name_list_dict[axis][0].find("<") == 0:
                x[0] += 0.5
            if isinstance(name_list_dict[axis][0], str) and (name_list_dict[axis][-1].find(">") == 0):
                x[-1] -= 0.5
        elif len(x) != len(name_list_dict[axis]):
            print("坐标的size和数据的size不匹配")
            return

        xticks = x[::spasify]

        if isinstance(x_one, datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis][::spasify], 3)
        elif axis.find("dayofyear") >= 0:
            xticks_labels = meteva.product.get_dayofyear_str_list(name_list_dict[axis][::spasify])
        else:
            xticks_labels = xticks_labels[::spasify]

        xticks_labels_None = []
        for i in range(len(xticks_labels)):
            xticks_labels_None.append("")

        if ncol is None:
            ncol = int(8 / width_one_subplot)
            nrow = int(math.ceil(subplot_num / ncol))
            ncol = int(math.ceil(subplot_num / nrow))
        else:
            nrow = int(math.ceil(len(name_list_dict[subplot]) / ncol))

        if width is None:
            width_fig = width_one_subplot * ncol
            if width_fig > 8: width_fig = 8
            if width_fig < 4: width_fig = 4
        else:
            width_fig = width

        height_axis = width_axis * 0.5
        height_hspace = sup_fontsize * 0.01
        height_suplegend = 1
        if height is None:
            height_fig = nrow * (height_axis + height_hspace) + height_suplegend
            if height_fig > 6: height_fig = 6
            if height_fig < 3: height_fig = 3
        else:
            height_fig = height

        fig = plt.figure(figsize=(width_fig, height_fig), dpi=dpi)
        x = np.arange(data.shape[2])
        hspace = height_hspace / (width_axis * 0.5)
        wspace = width_wspace / width_one_subplot

        plt.subplots_adjust(left=0, bottom=0.0, right=1.0, top=1 - height_suplegend / height_fig,
                            hspace=0.08, wspace=wspace)

        if bar_width is None:
            width = 0.7 / (legend_num + 2)
        else:
            width = bar_width
        ax_top = None
        for k in range(subplot_num):
            # print(data.shape)
            data_k = data[k, :, :]

            dat_bar_list = []
            dat_line_list = []
            for i in range(legend_num):
                if type_list[i] == "bar":
                    if log_y_bar:
                        data_k[i, data_k[i, :] == 0] = meteva.base.IV
                    dat_bar_list.append(data_k[i, :])
                else:
                    if log_y_line:
                        data_k[i, data_k[i, :] == 0] = meteva.base.IV
                    dat_line_list.append(data_k[i, :])

            dat_bar = np.array(dat_bar_list)
            dat_line = np.array(dat_line_list)

            if vmin_bar is None:
                dat_k0 = dat_bar[dat_bar != meteva.base.IV]
                if dat_k0.size > 0:
                    vmin1_bar = np.min(dat_k0)
                else:
                    vmin1_bar = 0
            else:
                if isinstance(vmin_bar, list):
                    if len(vmin_bar) != subplot_num:
                        print("vmin 参数的个数和 子图个数不一致，请重新设置")
                        return
                    else:
                        vmin1_bar = vmin_bar[k]
                else:
                    vmin1_bar = vmin_bar

            if vmax_bar is None:
                dat_k0 = dat_bar[dat_bar != meteva.base.IV]
                if dat_k0.size > 0:
                    vmax1_bar = np.max(dat_k0)
                else:
                    vmax1_bar = vmin1_bar + 0.1
            else:
                if isinstance(vmax_bar, list):
                    if len(vmax_bar) != subplot_num:
                        print("vmin 参数的个数和 子图个数不一致，请重新设置")
                        return
                    else:
                        vmax1_bar = vmax_bar[k]
                else:
                    vmax1_bar = vmax_bar

            dmax_bar = vmax1_bar - vmin1_bar

            if log_y_bar and vmin1_bar < 0:
                print("取对数坐标时数据的最小值不能<0")
            if vmin_bar is None:
                if log_y_bar:
                    pass
                    vmin1_bar = vmin1_bar * (vmin1_bar / vmax1_bar) ** 0.2
                else:
                    if vmin1_bar < 0:
                        vmin1_bar = vmin1_bar - 0.1 * dmax_bar
            if vmax_bar is None:
                if log_y_bar:
                    vmax1_bar = vmax1_bar * (vmax1_bar / vmin1_bar) ** 0.5
                else:
                    vmax1_bar = vmax1_bar + 0.5 * dmax_bar


            if vmin_line is None:
                dat_k0 = dat_line[dat_line != meteva.base.IV]
                if dat_k0.size > 0:
                    vmin1_line = np.min(dat_k0)
                else:
                    vmin1_line = 0
            else:
                if isinstance(vmin_line, list):
                    if len(vmin_line) != subplot_num:
                        print("vmin 参数的个数和 子图个数不一致，请重新设置")
                        return
                    else:
                        vmin1_line = vmin_line[k]
                else:
                    vmin1_line = vmin_line

            if vmax_line is None:
                dat_k0 = dat_line[dat_line != meteva.base.IV]
                if dat_k0.size > 0:
                    vmax1_line = np.max(dat_k0)
                else:
                    vmax1_line = vmin1_line + 0.1
            else:
                if isinstance(vmax_line, list):
                    if len(vmax_line) != subplot_num:
                        print("vmin 参数的个数和 子图个数不一致，请重新设置")
                        return
                    else:
                        vmax1_line = vmax_line[k]
                else:
                    vmax1_line = vmax_line

            dmax_line = vmax1_line - vmin1_line

            if log_y_line and vmin1_line < 0:
                print("取对数坐标时数据的最小值不能<0")
            if vmin_line is None:
                if log_y_line:
                    pass
                    vmin1_line = vmin1_line * (vmin1_line / vmax1_line) ** 0.2
                else:
                    vmin1_line = vmin1_line - 0.1 * dmax_line
            if vmax_line is None:
                if log_y_line:
                    vmax1_line = vmax1_line * (vmax1_line / vmin1_line) ** 0.5
                else:
                    vmax1_line = vmax1_line + 0.5 * dmax_line


            ax_one = plt.subplot(nrow, ncol, k + 1)
            if k == 0: ax_top = ax_one
            legend0 = str(name_list_dict[legend][0])
            if legend0.lower().find("ob") < 0 and legend0.find("观测") < 0 and legend0.find("实况") < 0 and legend0.find(
                    "零场") < 0:
                plt.bar(0, 0)
                plt.plot(0, 0)
            for i in range(legend_num):
                if type_list[i] == "bar":
                    x1 = x + (i - legend_num / 2 + 0.5) * width
                    dat0 = data[k, i, :]
                    y_plot = dat0[dat0 != meteva.base.IV]
                    x_plot = x1[dat0 != meteva.base.IV]
                    if color_list is None:
                        if meteva.base.plot_color_dict is not None and name_list_dict[legend][
                            i] in meteva.base.plot_color_dict.keys():
                            color_set1 = meteva.base.plot_color_dict[name_list_dict[legend][i]]
                            if k == 0:
                                plt.bar(x_plot, y_plot, width=width * 0.95, label=name_list_dict[legend][i],
                                        color=color_set1)
                            else:
                                plt.bar(x_plot, y_plot, width=width * 0.95, color=color_set1)
                        else:
                            if k == 0:
                                plt.bar(x_plot, y_plot, width=width * 0.95, label=name_list_dict[legend][i])
                            else:
                                plt.bar(x_plot, y_plot, width=width * 0.95)
                    else:
                        if k == 0:
                            plt.bar(x_plot, y_plot, width=width * 0.95, label=name_list_dict[legend][i],
                                    color=color_list[i])
                        else:
                            plt.bar(x_plot, y_plot, width=width * 0.95, color=color_list[i])
                    if tag >= 0:
                        # add data tag
                        delta = (vmax1_bar - vmin1_bar) / 20
                        for a, b in zip(x_plot, y_plot):
                            fmt_tag = "%." + str(tag) + "f"
                            plt.text(a, b + delta, fmt_tag % b, ha="center", va="bottom", fontsize=sup_fontsize * 0.6)

                    if len(dat0[dat0 == meteva.base.IV]) > 0:
                        x_iv = x1[dat0 == meteva.base.IV]
                        y_iv = np.zeros(x_iv.size)
                        plt.plot(x_iv, y_iv, "^", color='k')
            for i in range(legend_num):
                if type_list[i] != "bar":
                    dat0 = data[k, i, :]
                    index_iv = np.where(dat0 == meteva.base.IV)
                    if len(index_iv[0]) == 0:
                        if color_list is None:
                            if meteva.base.plot_color_dict is not None and name_list_dict[legend][i] in meteva.base.plot_color_dict.keys():
                                color_set1 = meteva.base.plot_color_dict[name_list_dict[legend][i]]
                                if k == 0:
                                    plt.plot(x, data[k, i, :], label=name_list_dict[legend][i], color=color_set1)
                                else:
                                    plt.plot(x, data[k, i, :], color=color_set1)
                            else:
                                if k == 0:
                                    plt.plot(x, data[k, i, :], label=name_list_dict[legend][i])
                                else:
                                    plt.plot(x, data[k, i, :])
                        else:
                            if k == 0:
                                plt.plot(x, data[k, i, :], label=name_list_dict[legend][i], color=color_list[i])
                            else:
                                plt.plot(x, data[k, i, :], color=color_list[i])
                    else:
                        dat0_all = set_plot_IV_with_out_start_end(dat0)
                        plt.plot(x, dat0_all, "--", linewidth=0.5, color="k")
                        x_iv = x[index_iv[0]]
                        dat0_iv = dat0_all[index_iv[0]]
                        plt.plot(x_iv, dat0_iv, "x", color='k',markersize = 1)
                        dat0_notiv = dat0.copy()
                        dat0_notiv[dat0_notiv == meteva.base.IV] = np.nan
                        if color_list is None:
                            if meteva.base.plot_color_dict is not None and name_list_dict[legend][i] in meteva.base.plot_color_dict.keys():
                                color_set1 = meteva.base.plot_color_dict[name_list_dict[legend][i]]
                                if k == 0:
                                    plt.plot(x, dat0_notiv, label=name_list_dict[legend][i], color=color_set1)
                                else:
                                    plt.plot(x, dat0_notiv, color=color_set1)
                            else:
                                if k == 0:
                                    plt.plot(x, dat0_notiv, label=name_list_dict[legend][i])
                                else:
                                    plt.plot(x, dat0_notiv)
                        else:
                            if k == 0:
                                plt.plot(x, dat0_notiv, label=name_list_dict[legend][i], color=color_list[i])
                            else:
                                plt.plot(x, dat0_notiv, color=color_list[i])

                    if tag >= 0:
                        for ii in range(len(dat0)):
                            a = x[ii]
                            b = dat0[ii]
                            if np.isnan(b) or b == meteva.base.IV: continue
                            va = "center"
                            if ii > 0 and ii < len(dat0) - 1:
                                if b > dat0[ii - 1] and b > dat0[ii + 1]:
                                    va = "bottom"
                                elif b < dat0[ii - 1] and b < dat0[ii + 1]:
                                    va = "top"
                            fmt_tag = "%." + str(tag) + "f"
                            plt.text(a, b, fmt_tag % b, ha="center", va=va,
                                     fontsize=sup_fontsize * 0.6)

            ki = k % ncol
            kj = int(k / ncol)
            knext_row = ki + (kj + 1) * ncol
            # print(knext_row)
            # print(subplot_num)
            if xlabel is None: xlabel = axis
            if knext_row >= subplot_num:
                # plt.xticks(x[::spasify], name_list_dict[axis][::spasify], fontsize=sup_fontsize * 0.8)
                plt.xticks(xticks, xticks_labels, fontsize=xticks_font)
                plt.xlabel(xlabel, fontsize=sup_fontsize * 0.9)
            else:
                plt.xticks(xticks, xticks_labels_None)
            xminorLocator = mpl.ticker.MultipleLocator(1)  # 将x轴次刻度标签设置xmi
            ax_one.xaxis.set_minor_locator(xminorLocator)
            plt.yticks(fontsize=sup_fontsize * 0.8)

            plt.ylabel(ylabel_line, fontsize=sup_fontsize * 0.9)
            if hline is not None:
                plt.axhline(hline, ls="--", c="k")
            if isinstance(title, list):
                if (len(title) != subplot_num):
                    print("子图数和设置的子图标题数不一致")
                    return
                title1 = title[k]
            else:
                if subplot_num > 1:
                    title1 = title + str(name_list_dict[subplot][k])
                else:
                    title1 = title
            if subplot_num > 1:
                y1 = 1 - 0.035 * sup_fontsize / (height_fig / nrow)
                plt.title(title1, fontsize=sup_fontsize, y=y1)
            else:
                plt.title(title1, fontsize=sup_fontsize)

            plt.xlim(-0.5, data.shape[2] - 0.5)

            # if log_y:
            #     for tick in ax_one.yaxis.get_major_ticks():
            #         tick.label1.set_fontproperties('stixgeneral')
            #     plt.yscale('log')
            # plt.ylim(vmin1, vmax1)
            # if grid is not None:
            #     if grid:
            #         if plot_type == "bar":
            #             plt.grid(axis="y")
            #         else:
            #             plt.grid()
            #     else:
            #         pass
            # else:
            #     if spasify > 2:
            #         if plot_type == "bar":
            #             plt.grid(axis="y")
            #         else:
            #             plt.grid()

        # print("a")
        if sup_title is not None:

            if legend_num == 1:
                strss = sup_title.split("\n")
                by = 1 - (height_suplegend - len(strss) * sup_fontsize * 0.01) / height_fig + 0.025
                plt.suptitle(sup_title, y=by, fontsize=sup_fontsize)
            else:
                width_suptitle = caculate_str_width(sup_title, sup_fontsize)
                if legend_col is None:
                    legend_col = int((width_fig - width_suptitle) * 12 / sup_fontsize)
                    if legend_col < 1: legend_col = 1
                    legend_row = int(math.ceil(legend_num / legend_col))
                    legend_col = int(math.ceil(legend_num / legend_row))
                else:
                    legend_row = int(math.ceil(legend_num / legend_col))
                strss = sup_title.split("\n")
                # by = 1 - (height_suplegend - len(strss) * sup_fontsize * 0.01) / height_fig + 0.025

                by = ax_top.bbox.ymax / fig.bbox.ymax + (len(strss) * sup_fontsize * 0.015 + 0.1) / height_fig
                plt.suptitle(sup_title, x=0, y=by, fontsize=sup_fontsize, horizontalalignment='left')

                # by = 1 - (height_suplegend - legend_row * sup_fontsize * 0.9 * 0.02) / height_fig + 0.05
                by = ax_top.bbox.ymax / fig.bbox.ymax + (legend_row * sup_fontsize * 0.7 * 0.02 + 0.15) / height_fig
                if subplot_num > 1:
                    fig.legend(fontsize=sup_fontsize * 0.7, ncol=legend_col, loc="upper right",
                               bbox_to_anchor=(1, by))
                else:
                    plt.legend(fontsize=sup_fontsize * 0.7, ncol=legend_col, loc="upper right")
        else:
            if legend_num > 1:
                if legend_col is None:
                    legend_col = int(width_fig * 8 / sup_fontsize)
                    if legend_col < 1: legend_col = 1
                    legend_row = int(math.ceil(legend_num / legend_col))
                    legend_col = int(math.ceil(legend_num / legend_row))
                else:
                    legend_row = int(math.ceil(legend_num / legend_col))
                # print(height_fig)
                by = ax_top.bbox.ymax / fig.bbox.ymax + (legend_row * sup_fontsize * 0.9 * 0.03 + 0.1) / height_fig

                # by = 1 - (height_suplegend - legend_row * sup_fontsize * 0.9 * 0.03) / height_fig + 0.025
                # print(by)

                if subplot_num > 1:
                    fig.legend(fontsize=sup_fontsize * 0.8, ncol=legend_col, loc="upper center",
                               bbox_to_anchor=(0.52, by))
                else:
                    plt.legend(fontsize=sup_fontsize * 0.8, ncol=legend_col, loc="upper center")

    else:
        print("array不能超过3维")
        return

    if save_path is None:
        show = True
    else:
        meteva.base.creat_path(save_path)
        plt.savefig(save_path,bbox_inches='tight')
        print("检验结果已以图片形式保存至" + save_path)
    if show:
        plt.show()
    plt.close()



def bar(array,name_list_dict = None,legend = None,axis = None,ylabel = "Value",vmin = None,vmax = None,ncol = None,grid = None,tag = -1,save_path = None,show = False
        ,dpi = 300,bar_width = None,title = "",spasify_xticks = None,sup_fontsize = 10,width = None,height = None,log_y = False,sup_title = None,xlabel = None,
        legend_col = None,color_list = None,hline = None,marker = None):

    plot_bar("bar",array = array,name_list_dict=name_list_dict,legend = legend,axis = axis,ylabel = ylabel,vmin= vmin,vmax = vmax,ncol =ncol,grid = grid,tag = tag,
             spasify_xticks = spasify_xticks,save_path = save_path,show = show,
             dpi = dpi,bar_width=bar_width,sup_fontsize= sup_fontsize,title=title,width = width,height = height,log_y = log_y,sup_title= sup_title,xlabel = xlabel,
             legend_col = legend_col,color_list=color_list,hline = hline,marker=marker)



def plot(array,name_list_dict = None,legend = None,axis = None,ylabel = "Value",vmin = None,vmax = None,ncol = None,grid = None,tag = -1,save_path = None,show = False,dpi = 300
         ,title ="",spasify_xticks = None,sup_fontsize = 10,width = None,height = None,log_y = False,sup_title = None,xlabel = None,legend_col = None,color_list = None,hline = None,
         marker = None):

    plot_bar("line",array,name_list_dict=name_list_dict,legend = legend,axis = axis,ylabel = ylabel,vmin= vmin,vmax = vmax,ncol =ncol,grid = grid,tag=tag ,
             spasify_xticks = spasify_xticks,save_path = save_path,show = show,
             dpi = dpi,sup_fontsize= sup_fontsize,title=title,width = width,height = height,log_y = log_y,sup_title = sup_title,xlabel = xlabel,
             legend_col =legend_col,color_list=color_list,hline = hline,marker = marker)


def myheatmap(ax_one,data_0,cmap,clevs,annot=1,fontsize=10):

    data_k = data_0.copy()
    nx = data_k.shape[1]
    ny = data_k.shape[0]
    x = np.arange(nx+1)-0.5
    y = np.arange(ny+1)-0.5

    data_k[data_k==meteva.base.IV] = np.nan
    norm = BoundaryNorm(clevs, ncolors=cmap.N - 1)
    im = ax_one.pcolormesh(x, y, data_k, cmap=cmap, norm=norm)
    im.update_scalarmappable()
    if annot is not None  and annot>=0:
        facecolors = im.get_facecolors()
        facecolors = facecolors.reshape(ny, nx, 4)
        fmt_tag = "%." + str(annot) + "f"
        for i in range(nx):
            for j in range(ny):
                data_ijk = data_k[j, i]
                if not np.isnan(data_ijk):
                    # 获取网格的颜色
                    color = facecolors[j, i, :]
                    # 计算亮度
                    rgb = mpl.colors.colorConverter.to_rgba_array(color)[:, :3]
                    rgb = np.where(rgb <= .03928, rgb / 12.92, ((rgb + .055) / 1.055) ** 2.4)
                    lum = rgb.dot([.2126, .7152, .0722])

                    text_color = ".15" if lum > .408 else "w"
                    ax_one.text(i, j, fmt_tag % data_ijk, ha="center", va="center",
                             fontsize=fontsize, c=text_color)
    fig = plt.gcf()
    fig.colorbar(im, ax=ax_one)

def mesh(array,name_list_dict = None,axis_x = None,axis_y = None,cmap = "rainbow",clevs = None,ncol = None,annot =None,save_path = None,show = False,dpi = 300,
         spasify_xticks = None,sup_fontsize = 10,title ="",width = None,height = None,rect = None,rect_color = "r"):

    shape = array.shape
    if len(array[array != meteva.base.IV]) == 0:
        print("所有的值都为缺失值")
        return

    if len(shape) == 3 or len(shape) == 2:
        if len(shape) == 2:
            array1 = array[np.newaxis,:]
            if name_list_dict is not None:
                name_list_dict1 = {}
                name_list_dict1["z"] = [0]
                for key in name_list_dict.keys():
                    name_list_dict1[key] = name_list_dict[key]
                name_list_dict = name_list_dict1

        else:
            array1 = array
        shape = array1.shape
        if name_list_dict is None:

            name_list_dict = {}
            name_list_dict["z"] = np.arange(shape[0])
            list1 = np.arange(shape[1]).tolist()
            list2 = []
            for lv in list1:
                list2.append("y_" + str(lv))
            name_list_dict["y"] = list2
            name_list_dict["x"] = np.arange(shape[2])
            legend = "y"
            axis_x = "x"
            subplot = "z"
        keys = list(name_list_dict.keys())
        if axis_y is None:
            if axis_x is None:
                axis_y = keys[1]
                axis_x = keys[2]
                subplot = keys[0]
            else:
                if axis_x == keys[2]:
                    axis_y = keys[1]
                    subplot = keys[0]
                elif axis_x == keys[1]:
                    axis_y = keys[2]
                    subplot = keys[0]
                else:
                    axis_y = keys[2]
                    subplot = keys[1]
        else:
            if axis_x is None:
                if axis_y == keys[0]:
                    axis_x = keys[2]
                    subplot = keys[1]
                elif axis_y == keys[1]:
                    axis_x = keys[2]
                    subplot = keys[0]
                else:
                    axis_x = keys[1]
                    subplot = keys[0]
            else:
                indexlist = [0, 1, 2]
                indexlist.remove(keys.index(axis_y))
                indexlist.remove(keys.index(axis_x))
                subplot = keys[indexlist[0]]
        if axis_y not in keys:
            print("axis_y 参数的取值必须是name_list_dict的key")
        if axis_x not in keys:
            print("axis_x 参数的取值必须是name_list_dict的key")
        newshape = (keys.index(subplot), keys.index(axis_y), keys.index(axis_x))
        #print(array1.shape)
        data = array1.transpose(newshape)
        legend_num = len(name_list_dict[axis_y])

        x_one = name_list_dict[axis_x][0]
        if isinstance(x_one, datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis_x], 3)
        else:
            xticks_labels = []
            for local in name_list_dict[axis_x]:
                xticks_labels.append(str(local))

        width_axis = meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize, legend_num)
        width_axis_labels = meteva.base.plot_tools.caculate_axis_width(xticks_labels, sup_fontsize, 1)

        width_wspace = sup_fontsize * 0.1
        width_one_subplot = width_axis + width_wspace
        if width_one_subplot < 1.5: width_one_subplot = 1.5
        subplot_num = len(name_list_dict[subplot])
        spasify = 1
        if ncol is not None:
            if width_one_subplot > 8/ ncol:
                spasify = int(math.ceil(width_axis_labels / (10 / ncol - width_wspace)))
                width_one_subplot = 8/ ncol
        else:
            if width_one_subplot > 8:
                spasify = int(math.ceil(width_axis_labels / (10 - width_wspace)))
                width_one_subplot = 8

        if spasify_xticks is not None:
            xticks_font = sup_fontsize * 1.0 * spasify_xticks * (width - width_wspace) / width_axis_labels
            spasify = spasify_xticks
        else:
            xticks_font = sup_fontsize * 0.8

        x = np.arange(len(name_list_dict[axis_x]))
        xticks = x[::spasify]
        if isinstance(x_one, datetime.datetime):
            xticks_labels = meteva.product.get_time_str_list(name_list_dict[axis_x][::spasify], 3)
        else:
            xticks_labels = xticks_labels[::spasify]

        xticks_labels_None = []
        for i in range(len(xticks_labels)):
            xticks_labels_None.append("")

        y = np.arange(len(name_list_dict[axis_y])+1) -0.5
        yticks = np.arange(len(name_list_dict[axis_y]))
        y_one = name_list_dict[axis_y][0]
        yticks_labels =[]
        if isinstance(y_one, datetime.datetime):
            for time1 in  name_list_dict[axis_y]:
                str1 = "%02d" % time1.day + "日" + "%02d" % time1.hour + "时"
                yticks_labels.append(str1)
        else:
            for local in name_list_dict[axis_y]:
                yticks_labels.append(str(local))

        if ncol is None:
            ncol = int(round(8 / width_one_subplot))

            nrow = int(math.ceil(subplot_num / ncol))
            ncol = int(math.ceil(subplot_num / nrow))
        else:
            nrow = int(math.ceil(len(name_list_dict[subplot]) / ncol))
        if width is None:
            width_fig = width_one_subplot * ncol
            if width_fig > 8:width_fig = 8
            if width_fig < 4: width_fig = 4
        else:
            width_fig = width


        height_axis = (width_one_subplot - width_wspace) * data.shape[1] / data.shape[2]
        height_hspace = sup_fontsize * 0.01
        height_suplegend = 0
        if height is None:
            height_fig = nrow * (height_axis + height_hspace) + height_suplegend
            if height_fig > 6:height_fig = 6
            if height_fig < 3: height_fig = 3
        else:
            height_fig = height

        fig = plt.figure(figsize=(width_fig, height_fig), dpi=dpi)
        x = np.arange(data.shape[2]+1) -0.5
        axes_list = []
        hspace = 0.1 * sup_fontsize * nrow/height_fig
        wspace = width_wspace / width_one_subplot

        plt.subplots_adjust(left=0, bottom=0.0, right=1.0, top=1 - height_suplegend / height_fig,
                            hspace=hspace, wspace=wspace)

        vmin =None
        vmax = None
        data = data.astype(np.float32)
        data[data == meteva.base.IV] = np.nan
        if not isinstance(cmap,list):
            data_copy = copy.deepcopy(data)
            data_copy[np.isnan(data_copy)] = meteva.base.IV
            vmin = np.min(data_copy[data_copy != meteva.base.IV])
            vmax = np.max(data_copy[data_copy != meteva.base.IV])
            cmap,clevs = meteva.base.color_tools.def_cmap_clevs(cmap=cmap, clevs=clevs, vmin=vmin, vmax=vmax)

        for k in range(subplot_num):
            data_k = data[k, :, :]
            if isinstance(cmap, list):
                cmap0 = cmap[k]
                if isinstance(clevs,list):
                    clevs0 = clevs[k]
                else:
                    clevs0 = clevs

                data_k_copy = copy.deepcopy(data_k)
                data_k_copy[np.isnan(data_k_copy)] = meteva.base.IV
                vmin = np.min(data_k_copy[data_k_copy != meteva.base.IV])
                vmax = np.max(data_k_copy[data_k_copy != meteva.base.IV])
            else:
                cmap0 = cmap
                clevs0 = clevs
            cmap1,clevs1= meteva.base.color_tools.def_cmap_clevs(cmap = cmap0,clevs=clevs0,vmin=vmin,vmax = vmax)
            ax_one = plt.subplot(nrow, ncol, k + 1)
            myheatmap(ax_one,data_k,cmap1,clevs1,annot,sup_fontsize)

            ki = k % ncol
            kj = int(k / ncol)
            knext_row = ki + (kj + 1) * ncol
            # print(knext_row)
            # print(subplot_num)
            plt.xticks(xticks, xticks_labels, fontsize=xticks_font)
            if knext_row >= subplot_num:
                # plt.xticks(x[::spasify], name_list_dict[axis][::spasify], fontsize=sup_fontsize * 0.8)

                plt.xlabel(axis_x, fontsize=sup_fontsize * 0.9)
            #else:
            #    plt.xticks(xticks, xticks_labels_None)
            xminorLocator = mpl.ticker.MultipleLocator(1)  # 将x轴次刻度标签设置xmi
            #ax_one.xaxis.set_minor_locator(xminorLocator)
            plt.yticks(yticks,yticks_labels,fontsize=sup_fontsize * 0.8)
            plt.ylabel(axis_y, fontsize=sup_fontsize * 0.9)
            if rect is not None:
                rect1 = patches.Rectangle((rect[0], rect[1]), rect[2], rect[3], linewidth=2, edgecolor=rect_color, facecolor='none')
                ax_one.add_patch(rect1)
            #plt.ylabel(ylabel, fontsize=sup_fontsize * 0.9)

            if isinstance(title, list):
                if (len(title) != subplot_num):
                    print("子图数和设置的子图标题数不一致")
                    return
                title1 = title[k]
            else:
                if subplot_num > 1:
                    title1 = title  + str(name_list_dict[subplot][k])
                else:
                    title1 = title
            plt.title(title1, fontsize=sup_fontsize)

    else:
        print("array只能绘制2维或3维数据")
        return

    if save_path is None:
        show = True
    else:
        meteva.base.creat_path(save_path)
        plt.savefig(save_path, bbox_inches='tight')
        print("检验结果已以图片形式保存至" + save_path)
    if show:
        plt.show()
    plt.close()




def mesh_obtime_time(sta0,save_dir = None,save_path = None,
                   clevs = None,cmap = None,show = False,xtimetype = "mid",dpi = 300,annot =None,
                     sup_fontsize = 10,title = "预报准确性和稳定性对比图",width = None,height = None,multiple = 1):


    sta = sta0.copy()
    sta.iloc[:,6:] *= multiple
    ids = list(set(sta.loc[:, "id"]))
    data_names = meteva.base.get_stadata_names(sta)
    times_fo = sta.loc[:, "time"].values
    times_fo = list(set(times_fo))
    if (len(times_fo) == 1):
        print("仅有单个起报时间的预报，程序退出")
        return
    times_fo.sort()
    times_fo = np.array(times_fo)
    #print(times_fo)

    dhs_fo = (times_fo[1:] - times_fo[0:-1])
    if isinstance(dhs_fo[0], np.timedelta64):
        dhs_fo = dhs_fo / np.timedelta64(1, 'h')
    else:
        dhs_fo = dhs_fo / datetime.timedelta(hours=1)
    dhs_fo_not0 = dhs_fo[dhs_fo != 0]
    dh_y = np.min(dhs_fo_not0)
    min_dtime = int(np.min(sta["dtime"]))


    ob_time_s = sta["time"] + sta["dtime"] * np.timedelta64(1, 'h')
    times_ob = list(set(ob_time_s.values))
    times_ob.sort()
    times_ob = np.array(times_ob)

    dhs_ob = (times_ob[1:] - times_ob[0:-1])
    if isinstance(dhs_ob[0], np.timedelta64):
        dhs_ob = dhs_ob / np.timedelta64(1, 'h')
    else:
        dhs_ob = dhs_ob / datetime.timedelta(hours=1)

    dhs_ob_not0 = dhs_ob[dhs_ob != 0]
    dh_x = meteva.base.tool.math_tools.greatest_common_divisor(dhs_ob_not0)
    #print(dh_x)
    np.sum(dhs_fo_not0)
    row = int(np.sum(dhs_fo_not0)/dh_y)+1
    col = int(np.sum(dhs_ob_not0)/dh_x)+1
    #print(row)
    t_ob = []
    for t in times_ob:
        t_ob.append(meteva.base.all_type_time_to_datetime(t))

    y_ticks = []
    t_fo0= meteva.base.all_type_time_to_datetime(times_fo[0])
    step = int(math.ceil(row / 40))

    if step !=1 :
        while step * dh_y % 3 !=0:
            step +=1

    y_plot = np.arange(0,row,step)+0.5
    for j in range(0,row,step):
        jr = row - j - 1
        time_fo = t_fo0 + datetime.timedelta(hours=1) * dh_y * jr
        hour = time_fo.hour
        day = time_fo.day
        #if ((j * int(dh_y)) % 3 == 0):
        str1 = "%02d"%day + "日" + "%02d"%hour + "时"
        #else:
        #    str1 = str(hour) + "时"
        #print(str1)
        y_ticks.append(str1)

    width0 = col * 0.1 + 2
    height0 = row * 0.1 + 2
    x_plot,x_ticks = meteva.product.get_x_ticks(times_ob,width0-2,row=3)
    #sup_fontsize = 10

    rate = max(width0/8, height0/6)
    if width is None:
        width = width0/rate
    if height is None:
        height = height0/rate

    sup_fontsize = sup_fontsize/rate

    x_plot /= dh_x
    #y_plot, y_ticks = meteva.product.get_y_ticks(times_fo, height)
    if xtimetype == "right":
        x_plot  = x_plot+0.5
    elif xtimetype == "left":
        x_plot = x_plot -0.5
    else:
        x_plot = x_plot


    nids = len(ids)
    nfo = len(data_names)
    if isinstance(title, list):
        if nids * nfo != len(title):
            print("手动设置的title数目和要绘制的图形数目不一致")
            return

    if save_path is not None:
        if isinstance(save_path,str):
            save_path = [save_path]
        if nids * nfo != len(save_path):
            print("手动设置的save_path数目和要绘制的图形数目不一致")
            return
    kk = 0
    #print(sta)
    dat = sta[data_names].values
    dat[np.isnan(dat)] = meteva.base.IV
    vmin = np.min(dat[dat != meteva.base.IV])
    vmax = np.max(dat[dat != meteva.base.IV])


    if cmap is None:
        cmap = "bwr"
    cmap_part,clevs_part = meteva.base.tool.color_tools.def_cmap_clevs(cmap=cmap,clevs=clevs,vmin=vmin,vmax = vmax)

    #if cmap is None:
    #    cmap = "bwr"
    #    cmap_part = cmap
    #if clevs is not None:
    #    clev_part, cmap_part = meteva.base.tool.color_tools.get_part_clev_and_cmap(clevs, cmap, vmax, vmin)
    vmax = clevs_part[-1]
    vmin = 2 * clevs_part[0] - clevs_part[1]

    if annot is None:
        if vmax>1:
            annot = 0
        else:
            annot = 1
    if col >= 120:
        annot = -1
    annot_f = annot
    fmt = "." + str(annot) + "f"
    annot_size = width * 50 / col
    if annot_size > height * 50 / row:
        annot_size = height * 50 / row
    if annot_size > 16:
        annot_size = 16
    annot = annot >= 0

    for d in range(nfo):
        data_name = data_names[d]
        sta_one_member = meteva.base.in_member_list(sta, [data_name])
        #meteva.base.set_stadata_names(sta_ob_part2, [data_name])
        #sta_one_member = meteva.base.combine_join(sta_ob_part2, sta_fo_all2)
        #以最近的预报作为窗口中间的时刻
        for id in ids:
            sta_one_id = meteva.base.in_id_list(sta_one_member,id)
            dat = np.ones((col, row)) * meteva.base.IV

            for j in range(row):
                jr = row - j - 1
                time_fo = times_fo[0] + np.timedelta64(1, 'h') * dh_y * jr
                sta_on_row = meteva.base.in_time_list(sta_one_id,time_fo)
                dhx0 = (time_fo - times_ob[0])/np.timedelta64(1, 'h')
                dhxs = sta_on_row["dtime"].values + dhx0
                index_i = (dhxs/dh_x).astype(np.int16)
                dat[index_i,j] = sta_on_row.values[:,-1]
            mask = np.zeros_like(dat.T)
            mask[dat.T == meteva.base.IV] = True

            f, ax2 = plt.subplots(figsize=(width, height), nrows=1, edgecolor='black',dpi = dpi)
            plt.subplots_adjust(left=0.1, bottom=0.15, right=0.98, top=0.90)

            #sns.heatmap(dat.T, ax=ax2, mask=mask, cmap=cmap_part, vmin=vmin, vmax=vmax, center=None, robust=False, annot=annot,fmt=fmt
            #, annot_kws = {'size': annot_size})
            myheatmap(ax2,dat.T,cmap_part,clevs_part,annot_f,annot_size)
            ax2.set_xlabel('实况时间',fontsize = sup_fontsize*0.9)
            ax2.set_ylabel('起报时间',fontsize = sup_fontsize*0.9)
            ax2.set_xticks(x_plot)
            ax2.set_xticklabels(x_ticks,rotation=360, fontsize=sup_fontsize*0.8)
            ax2.set_yticks(y_plot)
            ax2.set_yticklabels(y_ticks, rotation=360,fontsize = sup_fontsize * 0.8)

            ax2.grid(linestyle='--', linewidth=0.5)
            ax2.set_ylim(row-0.5, -0.5)
            ax2.set_title(title[kk], loc='left', fontweight='bold', fontsize= sup_fontsize)
            #rect = patches.Rectangle((0,0 ), col, row, linewidth=0.8, edgecolor='k', facecolor='none')
            #ax2.add_patch(rect)
            #plt.tick_params(top='on', right='on', which='both')  # 显示上侧和右侧的刻度
            plt.rcParams['xtick.direction'] = 'in'  # 将x轴的刻度线方向设置抄向内
            plt.rcParams['ytick.direction'] = 'in'  # 将y轴的刻度方知向设置向内

            save_path1 = None
            if(save_path is None):
                if save_dir is None:
                    show = True
                else:
                    id_str = ""
                    if id != meteva.base.IV:
                        id_str = "_"+str(id)
                    save_path1 = save_dir +"/" +data_name+id_str + ".png"
            else:
                save_path1 = save_path[kk]
            if save_path1 is not None:

                meteva.base.tool.path_tools.creat_path(save_path1)
                plt.savefig(save_path1,bbox_inches='tight')
                print("图片已保存至"+save_path1)
            if show:
                plt.show()
            plt.close()
            kk += 1
    return


def mesh_obtime_dtime(sta0,save_dir = None,save_path = None,
                   clevs = None,cmap = None,show = False,xtimetype = "mid",dpi = 300,annot =None,title = "预报准确性和稳定性对比图",
                      sup_fontsize = 10,width = None,height = None,multiple = 1):

    sta = sta0.copy()
    sta.iloc[:,6:] *= multiple
    ids = list(set(sta.loc[:, "id"]))
    data_names = meteva.base.get_stadata_names(sta)

    dhs_fo = sta.loc[:, "dtime"].values
    dhs_fo = list(set(dhs_fo))
    dhs_fo.sort()

    ob_time_s = sta["time"] + sta["dtime"] * np.timedelta64(1, 'h')
    times_ob = list(set(ob_time_s.values))
    times_ob.sort()
    times_ob = np.array(times_ob)

    dhs_ob = (times_ob[1:] - times_ob[0:-1])
    if isinstance(dhs_ob[0], np.timedelta64):
        dhs_ob = dhs_ob / np.timedelta64(1, 'h')
    else:
        dhs_ob = dhs_ob / datetime.timedelta(hours=1)


    dhs_ob_not0 = dhs_ob[dhs_ob != 0]

    dh_x = meteva.base.tool.math_tools.greatest_common_divisor(dhs_ob_not0)
    #print(dh_x)
    row = len(dhs_fo)
    col = int(np.sum(dhs_ob_not0)/dh_x)+1
    #print(row)
    t_ob = []
    for t in times_ob:
        t_ob.append(meteva.base.all_type_time_to_datetime(t))
    y_ticks = dhs_fo

    width0 = col * 0.1 + 2
    height0 = row * 0.1 + 2
    x_plot, x_ticks = meteva.product.get_x_ticks(times_ob, width0 - 2,row=3)
    #sup_fontsize = 10

    rate = max(width0 / 8, height0 / 6)
    if width is None:
        width = width0/rate
    if height is None:
        height = height0/rate

    sup_fontsize = sup_fontsize / rate


    x_plot /= dh_x
    #y_plot, y_ticks = meteva.product.get_y_ticks(times_fo, height)
    if xtimetype == "right":
        x_plot  = x_plot+0.5
    elif xtimetype == "left":
        x_plot = x_plot -0.5
    else:
        x_plot = x_plot



    nids = len(ids)
    nfo = len(data_names)
    if isinstance(title, list):
        if nids * nfo != len(title):
            print("手动设置的title数目和要绘制的图形数目不一致")
            return

    if save_path is not None:
        if isinstance(save_path,str):
            save_path = [save_path]
        if nids * nfo != len(save_path):
            print("手动设置的save_path数目和要绘制的图形数目不一致")
            return
    kk = 0

    dat = sta[data_names].values
    dat[np.isnan(dat)] = meteva.base.IV
    vmin = np.min(dat[dat != meteva.base.IV])
    vmax = np.max(dat[dat != meteva.base.IV])
    if cmap is None:
        cmap = "bwr"
    cmap_part,clevs_part = meteva.base.tool.color_tools.def_cmap_clevs(cmap=cmap,clevs=clevs,vmin=vmin,vmax = vmax)

    #if cmap is None:
    #    cmap = "bwr"
    #    cmap_part = cmap
    #if clevs is not None:
    #    clev_part, cmap_part = meteva.base.tool.color_tools.get_part_clev_and_cmap(clevs, cmap, vmax, vmin)
    vmax = clevs_part[-1]
    vmin = 2 * clevs_part[0] - clevs_part[1]

    if annot is None:
        if vmax>1:
            annot = 0
        else:
            annot = 1
    if col >= 120:
        annot = -1
    fmt = "." + str(annot) + "f"
    annot_f = annot
    annot_size = width * 50 / col
    if annot_size > height * 50 / row:
        annot_size = height * 50 / row
    if annot_size > 16:
        annot_size = 16
    annot = annot >= 0

    #print(times_ob[0])
    for d in range(nfo):
        data_name = data_names[d]
        sta_one_member = meteva.base.in_member_list(sta, [data_name])
        #meteva.base.set_stadata_names(sta_ob_part2, [data_name])
        #sta_one_member = meteva.base.combine_join(sta_ob_part2, sta_fo_all2)
        #以最近的预报作为窗口中间的时刻
        for id in ids:
            sta_one_id = meteva.base.in_id_list(sta_one_member,id)
            dat = np.ones((col, row)) * meteva.base.IV
            for j in range(row):
                sta_on_row = meteva.base.in_dtime_list(sta_one_id,dhs_fo[j])
                #print(sta_on_row)
                dhxs = (sta_on_row["time"].values - times_ob[0])/np.timedelta64(1, 'h') + dhs_fo[j]
                index_i = (dhxs/dh_x).astype(np.int16)
                dat[index_i,j] = sta_on_row.values[:,-1]
            mask = np.zeros_like(dat.T)
            mask[dat.T == meteva.base.IV] = True

            f, ax2 = plt.subplots(figsize=(width, height), nrows=1, edgecolor='black',dpi = dpi)
            plt.subplots_adjust(left=0.1, bottom=0.15, right=0.98, top=0.90)

            #sns.heatmap(dat.T, ax=ax2, mask=mask, cmap=cmap_part, vmin=vmin, vmax=vmax, center=None, robust=False, annot=annot,fmt=fmt
            #, annot_kws = {'size': annot_size})

            myheatmap(ax2,dat.T,cmap_part,clevs_part,annot_f,annot_size)
            ax2.set_xlabel('实况时间',fontsize = sup_fontsize*0.9)
            ax2.set_ylabel('预报时效',fontsize = sup_fontsize*0.9)
            ax2.set_xticks(x_plot)
            ax2.set_xticklabels(x_ticks,rotation=360, fontsize=sup_fontsize * 0.8)
            ax2.set_yticks(np.arange(len(y_ticks)))
            ax2.set_yticklabels(y_ticks, rotation=360, fontsize=sup_fontsize * 0.8)

            ax2.grid(linestyle='--', linewidth=0.5)
            ax2.set_ylim(row-0.5, -0.5)
            ax2.set_title(title[kk], loc='left', fontweight='bold', fontsize=sup_fontsize)
            #rect = patches.Rectangle((0,0 ), col, row, linewidth=0.8, edgecolor='k', facecolor='none')
            #ax2.add_patch(rect)
            #plt.tick_params(top='on', right='on', which='both')  # 显示上侧和右侧的刻度
            plt.rcParams['xtick.direction'] = 'in'  # 将x轴的刻度线方向设置抄向内
            plt.rcParams['ytick.direction'] = 'in'  # 将y轴的刻度方知向设置向内

            save_path1 = None
            if(save_path is None):
                if save_dir is None:
                    show = True
                else:
                    id_str = ""
                    if id != meteva.base.IV:
                        id_str = "_"+str(id)
                    save_path1 = save_dir +"/" +data_name+id_str + ".png"
            else:
                save_path1 = save_path[kk]
            if save_path1 is not None:

                meteva.base.tool.path_tools.creat_path(save_path1)
                plt.savefig(save_path1,bbox_inches='tight')
                print("图片已保存至"+save_path1)
            if show:
                plt.show()
            plt.close()
            kk += 1
    return

def mesh_time_dtime(sta0,save_dir = None,save_path = None,
                   clevs = None,cmap = None,show = False,xtimetype = "mid",dpi = 300,annot =None,sup_fontsize = 10,title = "预报准确性对比图",
                    width = None,height = None,add_min_xticks = False,multiple = 1):

    sta = sta0.copy()
    sta.iloc[:,6:] *= multiple
    ids = list(set(sta.loc[:, "id"]))
    data_names = meteva.base.get_stadata_names(sta)
    times_fo = sta.loc[:, "time"].values
    times_fo = list(set(times_fo))
    if (len(times_fo) == 1):
        print("仅有单个起报时间的预报，程序退出")
        return
    times_fo.sort()
    times_fo = np.array(times_fo)


    dhs_fo = sta.loc[:, "dtime"].values
    dhs_fo = list(set(dhs_fo))
    dhs_fo.sort(reverse = True)
    #print(times_fo)
    dhs_x = (times_fo[1:] - times_fo[0:-1])
    if isinstance(dhs_x[0], np.timedelta64):
        dhs_x = dhs_x / np.timedelta64(1, 'h')
    else:
        dhs_x = dhs_x / datetime.timedelta(hours=1)
    dhs_x_not0 = dhs_x[dhs_x != 0]


    dh_x = meteva.base.tool.math_tools.greatest_common_divisor(dhs_x_not0)

    #print(dh_x)
    row = len(dhs_fo)
    col = int(np.sum(dhs_x_not0)/dh_x)+1
    #print(row)
    t_ob = []
    for t in times_fo:
        t_ob.append(meteva.base.all_type_time_to_datetime(t))



    width0 = col * 0.15 + 2
    height0 = row * 0.15 + 2

    #sup_fontsize = 10

    rate = max(width0 / 8, height0 / 6)
    if width is None:
        width = width0/rate
    if height is None:
        height = height0/rate


    x_plot, x_ticks = meteva.product.get_x_ticks(times_fo, width - 2,row = 3)
    y_plot, y_ticks = meteva.product.get_y_ticks(dhs_fo, height,sup_fontsize * 0.8)

    #sup_fontsize = sup_fontsize / (width0/width)

    rate2 = sup_fontsize * len(x_ticks) * 0.05 / width
    if rate2 > 1:
        sup_fontsize = sup_fontsize/rate2

    x_plot /= dh_x
    #y_plot, y_ticks = meteva.product.get_y_ticks(times_fo, height)
    if xtimetype == "right":
        x_plot  = x_plot+0.5
    elif xtimetype == "left":
        x_plot = x_plot -0.5
    else:
        x_plot = x_plot


    nids = len(ids)
    nfo = len(data_names)
    if isinstance(title, list):
        if nids * nfo != len(title):
            print("手动设置的title数目和要绘制的图形数目不一致")
            return

    if save_path is not None:
        if isinstance(save_path,str):
            save_path = [save_path]
        if nids * nfo != len(save_path):
            print("手动设置的save_path数目和要绘制的图形数目不一致")
            return
    kk = 0

    dat = sta[data_names].values
    dat[np.isnan(dat)] = meteva.base.IV

    vmin = np.min(dat[dat != meteva.base.IV])
    vmax = np.max(dat[dat != meteva.base.IV])
    if cmap is None:
        cmap = "bwr"


    cmap_part,clevs_part = meteva.base.tool.color_tools.def_cmap_clevs(cmap=cmap,clevs=clevs,vmin=vmin,vmax = vmax)
    vmax = clevs_part[-1]
    vmin = 2 * clevs_part[0] - clevs_part[1]


    if annot is None:
        if vmax>1:
            annot = 0
        else:
            annot = 1
    if col >= 120:
        annot = -1

    annot_f = annot
    fmt = "." + str(annot) + "f"

    annot_size = width * 50 / col

    if annot_size > height * 50 / row:
        annot_size = height * 50 / row
    if annot_size > 16:
        annot_size = 16
    annot = annot >= 0


    #print(times_ob[0])
    for d in range(nfo):
        data_name = data_names[d]
        sta_one_member = meteva.base.in_member_list(sta, [data_name])
        #meteva.base.set_stadata_names(sta_ob_part2, [data_name])
        #sta_one_member = meteva.base.combine_join(sta_ob_part2, sta_fo_all2)
        #以最近的预报作为窗口中间的时刻
        for id in ids:
            sta_one_id = meteva.base.in_id_list(sta_one_member,id)
            dat = np.ones((col, row)) * meteva.base.IV
            for j in range(row):
                sta_on_row = meteva.base.in_dtime_list(sta_one_id,dhs_fo[j])
                #print(sta_on_row)
                dhxs = (sta_on_row["time"].values - times_fo[0])/np.timedelta64(1, 'h')
                index_i = (dhxs/dh_x).astype(np.int16)
                dat[index_i,j] = sta_on_row.values[:,-1]
            mask = np.zeros_like(dat.T)
            mask[dat.T == meteva.base.IV] = True


            #height = width * row / col + 2
            #print(width)
            #print(height)
            f, ax2 = plt.subplots(figsize=(width, height), nrows=1, edgecolor='black',dpi = dpi)
            plt.subplots_adjust(left=0.1, bottom=0.15, right=0.98, top=0.90)
            #norm = BoundaryNorm(clevs_part, ncolors=cmap_part.N - 1)

#            sns.heatmap(dat.T, ax=ax2, mask=mask, cmap=cmap_part, vmin=vmin, vmax=vmax, center=None, robust=False, annot=annot,fmt=fmt
#           , annot_kws = {'size': annot_size})
            myheatmap(ax2,dat.T,cmap_part,clevs_part,annot_f,annot_size)

            ax2.set_xlabel('起报时间',fontsize = sup_fontsize * 0.9)
            ax2.set_ylabel('预报时效',fontsize = sup_fontsize * 0.9)
            ax2.set_xticks(x_plot)
            ax2.set_xticklabels(x_ticks,rotation=360, fontsize=sup_fontsize * 0.8)
            if add_min_xticks:ax2.set_xticks(np.arange(max(x_plot)+1))

            ax2.set_yticks(y_plot)
            ax2.set_yticklabels(y_ticks, rotation=360, fontsize=sup_fontsize * 0.8)

            ax2.grid(linestyle='--', linewidth=min(0.5,2*width/col))
            ax2.set_ylim(row-0.5, -0.5)
            ax2.set_title(title[kk], loc='left', fontweight='bold', fontsize=sup_fontsize)
            #rect = patches.Rectangle((-0.5,-0.5), col, row+, linewidth=0.8, edgecolor='k', facecolor='none')
            #ax2.add_patch(rect)
            #plt.tick_params(top='on', right='on', which='both')  # 显示上侧和右侧的刻度
            plt.rcParams['xtick.direction'] = 'in'  # 将x轴的刻度线方向设置抄向内
            plt.rcParams['ytick.direction'] = 'in'  # 将y轴的刻度方知向设置向内

            save_path1 = None
            if(save_path is None):
                if save_dir is None:
                    show = True
                else:
                    id_str = ""
                    if id != meteva.base.IV:
                        id_str = "_"+str(id)
                    save_path1 = save_dir +"/" +data_name+id_str + ".png"
            else:
                save_path1 = save_path[kk]
            if save_path1 is not None:

                meteva.base.tool.path_tools.creat_path(save_path1)
                plt.savefig(save_path1,bbox_inches='tight')
                print("图片已保存至"+save_path1)
            if show:
                plt.show()
            plt.close()
            kk += 1
    return


def barbs_grid_wind(grid_wind,width = None,height = None,sup_fontsize = 12,dpi = 300,skip = None,save_path = None,show = False):
    grid1 = meteva.base.get_grid_of_data(grid_wind)
    axs = meteva.base.creat_axs(1, map_extend=grid1, add_minmap=False, ncol=2, width=width,height=height,sup_fontsize=sup_fontsize,dpi=dpi)
    meteva.base.add_barbs(axs[0], grid_wind,skip=skip)

    if save_path is None:
        show = True
    else:
        meteva.base.creat_path(save_path)
        plt.savefig(save_path,bbox_inches='tight')
        print("检验结果已以图片形式保存至" + save_path)
    if show:
        plt.show()
    plt.close()


def add_scatter(ax,map_extend,sta0,cmap = None,clevs = None,point_size = None,fix_size = True,title = None,threshold = 2,min_spot_value = 0,mean_value = 2,
                grid = False,add_colorbar = True,alpha = None):
    sta = sta0
    if isinstance(map_extend, list):
        slon = map_extend[0]
        elon = map_extend[1]
        slat = map_extend[2]
        elat = map_extend[3]
        rlon = elon - slon
        rlat = elat - slat
    else:
        slon = map_extend.slon
        slat = map_extend.slat
        elon = map_extend.elon
        elat = map_extend.elat
        rlon = map_extend.elon - map_extend.slon
        rlat = map_extend.elat - map_extend.slat

    ax.set_xlim((slon, elon))
    ax.set_ylim((slat, elat))

    sta_without_iv = meteva.base.sele.not_IV(sta)

    values = sta_without_iv.iloc[:, -1].values

    vmax_v = np.max(sta_without_iv.iloc[:,-1].values)
    vmin_v = np.min(sta_without_iv.iloc[:,-1].values)

    cmap1, clevs1 = meteva.base.tool.color_tools.def_cmap_clevs(cmap=cmap, clevs=clevs, vmin=vmin_v, vmax=vmax_v)

    norm = BoundaryNorm(clevs1, ncolors=cmap1.N - 1)
    fig = plt.gcf()
    map_width = ax.bbox.width/fig.dpi

    if point_size is None:
        sta_id1 = sta0.drop_duplicates(['id'])
        sta_dis = meteva.base.sta_dis_ensemble_near_by_sta(sta_id1, nearNum=2)
        dis_values = sta_dis["data1"].values
        dis_values.sort()
        dis1 = dis_values[int(len(dis_values) * 0.02) + 1]/1.2
        point_size = (map_width * dis1 / rlon) ** 2
        # point_size = 100 * map_area / len(sta.index)
        # print("**************")
        # print(point_size)
        if (point_size > 30): point_size = 30
        if (point_size < 0.5):
            point_size = 0.5
            if alpha is None:
                alpha = 0.5
        # point_size *=3
        #left_low = (width + 0.1 - right_plots_width) / width


    x = sta_without_iv.loc[:, "lon"].values
    y = sta_without_iv.loc[:, "lat"].values
    colors = values
    if isinstance(fix_size, bool):
        if fix_size:
            im = ax.scatter(x, y, c=colors, cmap=cmap1, norm=norm, s=point_size,edgecolors = "face",alpha = alpha)
        else:
            area = point_size * np.abs(values - min_spot_value) / mean_value
            if (threshold is not None):
                area[np.abs(values - min_spot_value) < threshold] *= 0.1
            im = ax.scatter(x, y, c=colors, cmap=cmap1, norm=norm, s=area,edgecolors  = 'face',alpha = alpha)
            if grid: plt.grid()
    else:
        im = ax.scatter(x, y, c=colors, cmap=cmap1, norm=norm, s=fix_size,edgecolors  = 'face',alpha = alpha)


    if add_colorbar:
        width = fig.bbox.width / fig.dpi
        height = fig.bbox.height / fig.dpi
        location = [ax.bbox.x1 / fig.dpi / width + 0.005, ax.bbox.y0 / fig.dpi / height, 0.01,
                    ax.bbox.height / fig.dpi / height]

        if (add_colorbar):
            colorbar_position = fig.add_axes(location)  # 位置[左,下,宽,高]
            plt.colorbar(im, cax=colorbar_position)
    return im



